Postgresql源码(115)LLVM JIT运行逻辑分析(上)

1 JIT入口开关

  1. 总入口: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;}

2 从表达式堆栈进入JIT逻辑jit_compile_expr

《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...

3 jit_compile_expr初始化加载llvmjit.so

jit_compile_exprprovider_initload_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_exprprovider_initprovider.compile_expr(state)  -> llvm_compile_expr

4 llvm_compile_expr执行初始化llvm_create_context

llvm_create_context初始化生成LLVMJitContext结构:

typedef struct JitContext
{/* see PGJIT_* above */int			flags;ResourceOwner resowner;JitInstrumentation instr;
} JitContext;typedef struct LLVMJitContext
{JitContext	base;               // 上面的JIT FLAG、ResourceOwnersize_t		module_generation;  // 当前context存了几个Module?LLVMModuleRef module;           // 当前正在使用的modulebool		compiled;           // 已经编译过了?List	   *handles;            // 所有挂在当前context下的module
} LLVMJitContext;

llvm_create_context初始化流程

llvm_create_contextllvm_session_initialize【库函数】LLVMInitializeNativeTarget【库函数】LLVMInitializeNativeAsmPrinter【库函数】LLVMInitializeNativeAsmParser【库函数】LLVMContextSetOpaquePointers读取llvmjit_types.bc中需要的类型、函数签名:llvm_create_typesLLVMCreateMemoryBufferWithContentsOfFileLLVMParseBitcode2LLVMDisposeMemoryBuffer【库函数】LLVMGetTargetFromTriple...【库函数】LLVMLoadLibraryPermanentlyllvm_ts_context = LLVMOrcCreateNewThreadSafeContextllvm_opt0_orc = llvm_create_jit_instance【库函数】若干传入机器信息,构造LLVMJIT环境【库函数】若干LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine【库函数】若干LLVMOrcCreateLLJITllvm_opt3_orc = llvm_create_jit_instance【库函数】若干传入机器信息,构造LLVMJIT环境【库函数】若干LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine【库函数】若干LLVMOrcCreateLLJITResourceOwnerEnlargeJIT

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能识别的类型、函数。

5 llvm_compile_expr创建module

创建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;
}

在这里插入图片描述

6 llvm_compile_expr新增函数到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;elseb_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;}

7 (核心步骤)ExecRunCompiledExpr对module进行编译、优化、执行

ExecRunCompiledExpr找到jit函数并执行,惰性编译、优化。

ExecRunCompiledExprllvm_get_function重要:llvm_compile_moduleLLVMOrcLLJITLookup

在找函数执行时,编译这一步是核心逻辑,编译会对上面逻辑进行优化处理:

llvm_compile_modulellvm_inlinellvm_optimize_module

优化一:llvm_inline

llvm_build_inline_plan会查询module里面的function,到函数目录查找对应的bc文件,并加载bc文件中函数的逻辑(增加LLVM编译后,所有源码文件都会用clang额外生成一个bc文件,提供给inline使用)。function_inlinable函数会检查当前函数引用的其他函数时候能inline。

优化二:llvm_optimize_module

将IR过一遍PASS,下一篇继续分析后面的流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/153107.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络监控工具 - iftop

iftop 是一个基于 libpcap 库的网络流量监控工具。它通过监听指定网络接口上的数据包&#xff0c;并分析这些数据包的源地址、目标地址、源端口、目标端口、协议等信息&#xff0c;从而实时显示网络流量的相关统计信息。 安装 在大多数Linux发行版中&#xff0c;您可以使用包管…

【排序算法】冒泡排序

文章目录 一&#xff1a;排序算法1.1 介绍1.2 分类 二&#xff1a;冒泡排序2.1 基本介绍2.2 图解冒泡排序算法2.3 代码实现 三&#xff1a;算法性能分析3.1 时间复杂度3.2 空间复杂度 一&#xff1a;排序算法 1.1 介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将…

upload-labs靶场通关

文章目录 Pass-01 前端检测&#xff08;JS检测&#xff09;1.1 原理分析1.2 实验 Pass-02 后端检测&#xff08;MIME检测&#xff09;2.1 原理分析2.2 实验 Pass-03 后端检测&#xff08;黑名单绕过&#xff0c;特殊后缀名&#xff09;3.1 原理分析3.2 实验 Pass-04 后端检测&a…

【力扣-每日一题】2034. 股票价格波动

class StockPrice { private:unordered_map<int,int> mp; //存储日期及其对应的价格multiset<int> st; //存储所有价格int last_day; //最新一天 public:StockPrice() {this->last_day0;}void update(int timestamp, int price) {if(mp.find(timestamp)!mp…

leetCode 1143.最长公共子序列 动态规划 + 滚动数组

1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串…

大数据—数据透析表常见使用(手把手详解)

我的个人主页&#xff1a;☆光之梦☆_C语言基础语法&#xff08;超详细&#xff09;,【java入门】语法总结-CSDN博客 创作不易&#xff0c;如果能帮到你就好 注&#xff1a;你的 &#x1f44d;点赞 ⭐收藏 &#x1f4dd;评论 是对博主最大的支持与鼓励喔 目录 一、创建数据透…

【微服务】七. http客户端Feign

7.1 基于Feign远程调用 RestTimeplate方式调用存在的问题 先来看以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http://userservice/user"order.getUserId(); User user restTemplate.getForObject(url,User.class);存在下面的问题&#xf…

Vue Router的进阶

进阶 导航守卫 官方文档上面描述的会比较深奥&#xff0c;而守卫类型也比较多&#xff0c;其中包含了全局前置守卫、全局解析守卫、全局后置钩子、路由独享守卫、组件内守卫。每一种守卫的作用和用法都不相同。这会使得大家去学习的时候觉得比较困难&#xff0c;这边主要介绍…

CentOS Stream9 安装远程桌面服务 Xrdp

1. 安装 XRDP 若服务器本身没有桌面则首先需要安装本地桌面&#xff1a; yum -y groups install "GNOME Desktop" startx配置源&#xff1a; dnf install epel-release安装 xrdp dnf install xrdp 2. 配置 Xrdp Xrdp 配置文件位于 /etc/xrdp 目录中。对于常规 X…

HTTP长连接实现原理

1. HTTP长连接和短连接的定义 HTTP长连接 浏览器向服务器进行一次HTTP会话访问后&#xff0c;并不会直接关闭这个连接&#xff0c;而是会默认保持一段时间&#xff0c;那么下一次浏览器继续访问的时候就会再次利用到这个连接。在HTTP/1.1版本中&#xff0c;默认的连接都是长连…

计算机算法分析与设计(8)---图像压缩动态规划算法(含C++)代码

文章目录 一、知识概述1.1 问题描述1.2 算法思想1.3 算法设计1.4 例题分析 二、代码 一、知识概述 1.1 问题描述 1. 一幅图像的由很多个像素点构成&#xff0c;像素点越多分辨率越高&#xff0c;像素的灰度值范围为0~255&#xff0c;也就是需要8bit来存储一个像素的灰度值信息…

New Journal of Physics:不同机器学习力场特征的准确性测试

文章信息 作者&#xff1a;Ting Han1, Jie Li1, Liping Liu2, Fengyu Li1, * and Lin-Wang Wang2, * 通信单位&#xff1a;内蒙古大学物理科学与技术学院、中国科学院半导体研究所 DOI&#xff1a;10.1088/1367-2630/acf2bb 研究背景 近年来&#xff0c;基于DFT数据的机器学…

教你如何『SSH』远程连接『内网』服务器

前言 最近博主实验室要搬家&#xff0c;因为服务器只有连接内网才能使用&#xff0c;所以搬走之后就无法在公网连接使用服务器&#xff0c;确实是让人非常苦恼&#xff0c;所以本文将会主要讲解如何使用公网服务器 SSH 连接内网服务器 系统配置 内网服务器&#xff1a;Ubuntu …

川西旅游网系统-前后端分离(前台vue 后台element UI,后端servlet)

前台&#xff1a;tour_forword: 川西旅游网前端----前台 (gitee.com) 后台&#xff1a;tour_back: 川西旅游网-------后台 (gitee.com) 后端 &#xff1a;tour: 川西旅游网------后端 (gitee.com)

记录本地部署Stable-diffusion所依赖的repositories和一些插件

今天按照其他文章的步骤拉取好了https://github.com/AUTOMATIC1111/stable-diffusion-webui后&#xff0c;点击webui-user.bat后发现&#xff0c;repositories和models还得慢慢拉取&#xff0c;好吧&#xff0c;GitHub Desktop&#xff0c;启动&#xff01; BLIP: https://git…

visual studio解决bug封装dll库

1.速度最大化 O2 2.设置输出目录 配置属性/常规/输出目录 链接器/常规/输出dll文件 链接器/调试/输出程序数据库pdb文件 链接器/高级/导入库 3.输出X86 X64分别对应的dll、lib、pdb 然后修改更新说明 更新说明格式如下&#xff1a; 4.将库提交到FTP每日更新库文档下 和测试交接…

IIC总线

IIC总线原理 时序图作业 MPU6050 MPU6050是一个运动处理传感器&#xff0c;其内部集成了3轴加速度传感器 和3轴陀螺仪&#xff08;角速度传感器&#xff09;,以及一个可扩展数字运动处理器

idea compile项目正常,启动项目的时候build失败,报“找不到符号”等问题

1、首先往上找&#xff0c;看能不能找到如下报错信息 You aren’t using a compiler supported by lombok, so lombok will not work and has been disabled. 2、这种问题属于lombok编译失败导致&#xff0c;可能原因是依赖jar包没有更新到最新版本 3、解决方案 1&#xff09…

三十三、【进阶】索引的分类

1、索引的分类 &#xff08;1&#xff09;总分类 主键索引、唯一索引、常规索引、全文索引 &#xff08;2&#xff09;InnoDB存储引擎中的索引分类 2、 索引的选取规则(InnoDB存储引擎) 如果存在主键&#xff0c;主键索引就是聚集索引&#xff1b; 如果不存在主键&#xff…

使用Java操作Redis

要在Java程序中操作Redis可以使用Jedis开源工具。 一、jedis的下载 如果使用Maven项目&#xff0c;可以把以下内容添加到pom中 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId>…