导航:首页 > 源码编译 > 做编译器优化有前途吗

做编译器优化有前途吗

发布时间:2025-02-17 02:50:34

❶ 浅谈vue3的编译优化

编译优化:编译器将模版编译为渲染函数的过程中,尽可能地提取关键信息,并以此指导生成最优代码的过程。

优化的方向:尽可能地区分动态内容和静态内容,并针对不同的内容采用不同的优化策略

1.动态节点收集与补丁标志1.1传统diff算法的问题

比对新旧两棵虚拟DOM树的时候,总是要按照虚拟DOM的层级结构“一层一层”地遍历

<divid="foo"><pclass="bar">{{text}}</p></div>

上面这段代码中,当响应式数据text值发生变化的时候,最高效的更新方式是直接设置p标签的文本内容

传统Diff算法做不到如此高效,当text值发生变化的时候,会产生一颗新的虚拟DOM树,对比新旧虚拟DOM过程如下:

对比div节点,以及该节点的属性和子节点

对比p节点,以及该节点的属性和子节点

对比p节点的文本子节点,如果文本子节点的内容变了,则更新,否则什么都不做

可以发现,有很多无意义的对比操作。

总结:

传统diff算法的问题:无法利用编译时提取到的任何关键信息,导致渲染器在运行时不会去做相关的优化。

vue3的编译器会将编译得到的关键信息“附着”在它生成的虚拟DOM上,传递给渲染器,执行“快捷路径”。

1.2Block与PatchFlags

传统Diff算法无法避免新旧虚拟DOM树间无用的比较操作,是因为运行时得不到足够的关键信息,从而无法区分动态内容和静态内容。换句话说,只要运行时能够区分动态内容和静态内容,就可以实现极简的优化策略

举个例子:

<div><div>foo</div><p>{{bar}}</p></div>

只有{{bar}}是动态的内容。理想情况下,当数据bar的值变化时,只需要更新p标签的文本节点即可。为了实现这个目标,需要提供信息给运行时

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}

可以发现,虚拟节点多了一个额外的属性,即patchFlag(补丁标志),存在该属性,就认为是动态节点

patchFlag(补丁标志)可以理解为一系列的数字标记,含义如下

constPatchFlags={TEXT:1,//代表节点有动态的textContentCLASS:2,//代表元素有动态的class绑定STYLE:3//其他。。。}

可以在虚拟节点的创建阶段,把它的动态子节点提取出来,并存储到该虚拟节点的dynamicChildren数组中

constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点],//将children中的动态节点提取到dynamicChildren数组中dynamicChildren:[{tag:'p',children:ctx.bar,patchFlag:PatchFlags.TEXT}]}

Block定义:带有dynamicChildren属性的虚拟节点称为“块”,即(Block)

一个Block本质上也是一个虚拟DOM,比普通的虚拟节点多处一个用来存储动态节点的dynamicChildren属性。(能够收集所有的动态子代节点)

渲染器的更新操作会以Block为维度。当渲染器在更新一个Block时,会忽略虚拟节点的children数组,直接找到dynamicChildren数组,并只更新该数组中的动态节点。跳过了静态内容,只更新动态内容。同时,由于存在对应的补丁标志,也能够做到靶向更新。

Block节点有哪些:模版根节点、带有v-for、v-if/v-else-if/v-else等指令的节点

1.3收集动态节点

编译器生成的渲染函数代码中,不会直接包含用来描述虚拟节点的数据结构,而是包含着用来创建虚拟DOM节点的辅助函数,如下

render(){returncreateVNode('div',{id:'foo'},[createVNode('p',null,'text')])}functioncreateVNode(tag,props,children){constkey=props&&props.keyprops&&deleteprops.key//省略部分代码return{tag,props,children,key}}

createVNode的返回值是一个虚拟DOM节点

举个例子:

<divid="foo"><pclass="bar">{{bar}}</p></div>

上面模版生成带有补丁标志的渲染函数如下:

render(){returncreateVNode('div',{id:'foo'},[createVNode('p',{class:'bar'},text,PatchFlags.TEXT)])}

怎么将根节点变成一个Block,如何将动态子代节点收集到该Block的dynamicChildren数组中?

可以发现,在渲染函数内,对createVNode函数的调用是层层嵌套结构,执行顺序是内层先执行,外层再执行,当外层createVNode函数执行时,内层的createVNode函数已经执行完毕了。因此,为了让外层Block节点能够收集到内层动态节点,需要一个栈结构的数据来临时存储内层的动态节点。代码实现如下:

//动态节点constdynamicChildrenStack=[]//当前动态节点集合letcurrentDynamicChildren=null//openBlock用来创建一个新的动态节点集合,并将该集合压入栈中functionopenBlock(){dynamicChildrenStack.push((currentDynamicChildren=[]))}//closeBlock用来通过openBlock创建的动态节点集合从栈中弹出functioncloseBlock(){currentDynamicChildren=dynamicChildrenStack.pop()}

然后调整createVNode函数

<div><div>foo</div><p>{{bar}}</p></div>0

接着调整

<div><div>foo</div><p>{{bar}}</p></div>11.4.渲染器的运行时支持

传统的节点更新方式如下:

<div><div>foo</div><p>{{bar}}</p></div>2

优化后的更新方式,直接对比动态节点

<div><div>foo</div><p>{{bar}}</p></div>3

存在对应的补丁标志,可以针对性地完成靶向更新

<div><div>foo</div><p>{{bar}}</p></div>42.Block树

除了模版的根节点是Block外,带有结构化指令的节点,如:v-if、v-for,也都应该是Block

2.1带有v-if指令的节点<div><div>foo</div><p>{{bar}}</p></div>5

假设只有最外层的div标签会作为Block,那么变量foo的值为true还是false,block收集到的动态节点都是一样的,如下:

<div><div>foo</div><p>{{bar}}</p></div>6

这意味着,在Diff阶段不会更新。显然,foo不同值下,一个是section,一个是div,是不同标签,是需要更新的。

再举个例子:

<div><div>foo</div><p>{{bar}}</p></div>7

一样会导致更新失败

问题在于:dynamicChildren收集的动态节点是忽略虚拟DOM树层级的,结构化指令会导致更新前后模版的结构发生变化,即模版结构不稳定

解决方法:让带有v-if/v-else-if/v-else等结构化指令的节点也作为Block即可,如下所示

<div><div>foo</div><p>{{bar}}</p></div>8<div><div>foo</div><p>{{bar}}</p></div>9

在Diff过程中,渲染器根据key值区分,使用新的Block替换旧的Block

2.2带有v-for指令的节点

带有v-for指令的节点也会让虚拟DOM树变得不稳定

例子:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}0

list的值由[1,2]变成[1]

更新前后对应的Block树如下:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}1

更新前后,动态节点数量不一致,无法进行diff操作(diff操作的前提是:操作的节点必须是同层级节点,dynamicChildren不一定是同层级的)

解决方法:让v-for指令的标签也作为Block角色,保证虚拟DOM树具有稳定的结构,无论v-for在运行时怎样变化。如下:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}2

由于v-for指令渲染的是一个片段,所以类型用Fragment

2.3Fragment的稳定性//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}3

发现Fragment本身收集的动态节点存在结构是不稳定的情况

结构不稳定:指更新前后一个block的dynamicChildren数组中收集的动态节点的数量或顺序不一致

这种情况无法直接进行靶向更新

解决方法:回退到传统虚拟DOM的Diff手段,即直接使用Fragment的children而非dynamicChildren来进行Diff操作

Fragment的子节点仍然可以是由Block组成的数组

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}4

当Fragment的子节点更新时,就可以恢复优化模式

有稳定的Fragment吗?如下:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}5

稳定的Fragment,可以使用优化模式

vue3模版中的多个根节点,也是稳定的Fragment

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}63.静态提升

减少更新时创建虚拟DOM带来的性能开销和内存占用

如:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}7

没有静态提升时,渲染函数是:

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}8

响应式数据title变化后,整个渲染函数会重新执行

把纯静态的节点提升到渲染函数之外

//传统虚拟DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}9

响应式数据title变化后,不会重新创建静态的虚拟节点

注:静态提升是以树为单位的

包含动态绑定的节点本身不会被提升,但是该节点上的静态属性是可以被提升的

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}0

可以减少创建虚拟DOM产生的开销以及内存占用

4.预字符串化

基于静态提升,进一步采用预字符串化优化。

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}1

采用静态提升优化策略后

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}2

采用预字符串化将这些静态节点序列化为字符串,并生成一个Static类型的VNode

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}3

优势:

大块的静态内容可以通过innerHTML设置,在性能上有一定优势

减少创建虚拟节点产生的性能开销

减少内存占用

5.缓存内联事件处理函数//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}4//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}5

每次重新渲染时,都会为Com组件创建一个全新的props对象。同时,props对象中onChange属性的值也会是全新的函数。造成额外的性能开销

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}66.v-once

v-once可以对虚拟DOM进行缓存

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}7

由于节点被缓存,意味着更新前后的虚拟节点不会发生变化,因此也就不需要这些被缓存的虚拟节点参与Diff操作了。编译后的结果如下:

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}8

v-once包裹的动态节点不会被父级Block收集,因此不会参与Diff操作

v-once指令通常用于不会发生改变的动态绑定中,例如绑定一个常量

//编译优化后constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//这是动态节点]}9

v-once带来的性能提升

避免组件更新时重新创建虚拟DOM带来的性能开销。因为虚拟DOM被缓存了,所以更新时无需重新创建

避免无用的Diff开销。因为被v-once标记的虚拟DOM树不会被父级Block节点收集

7.总结

1.vue3提出了Block的概念,利用Block树及补丁标志

2.静态提升:可以减少更新时创建虚拟DOM产生的性能开销和内存占用

3.预字符串化:在静态提升的基础上,对静态节点进行字符串化。这样做能够减少创建虚拟节点产生的性能开销以及内存占用

4.缓存内联事件处理函数:避免造成不必要的组件更新

5.v-once指令:缓存全部或部分虚拟节点,能够避免组件更新时重新创建虚拟DOM带来的性能开销,也可以避免无用的Diff操作

原文:https://juejin.cn/post/7101859824203202568

❷ 应用编译优化三种模式

应用编译优化三种模式分别是:编译时间优化模式、执行时间优化模式和代码大小优化模式。
1、编译时间优化模式:关注编译速度的提升,以缩短应用程序高脊的编译时间为目标。在这种模式下,编译器会减少编译时间,会降低应用程序的执行效率。
2、执行时间优化模式:关注应用程序的执行效率,以提高应用程序的性能为目标。在这种模式下,编译器会优化应用程序的代码,以提高执行效率,会增加编译时间。
3、代码大小优化模式:关注应用程序的大小,以减小应兆培用程序的体积为目标。族念唯在这种模式下,编译器会减小应用程序的代码大小,以减小应用程序的体积,会降低应用程序的执行效率。

❸ 深度学习推理引擎的一些思考

深度学习推理引擎,特别是走编译优化路径的引擎,是解决现代深度学习应用的关键技术之一。作为曾经的传统编译器开发者,我见证了从传统编译器到深度学习领域的转变。在阿里巴巴工作期间,我积极推动基于编译优化的深度学习推理引擎的开发,这一领域在短短几年内已经取得了显着进展。

在18年初加入阿里巴巴时,基于编译优化的深度学习推理引擎并不占据主流地位,当时流行的解决方案是TFLite和NCNN等框架,它们依赖高效GEMM加速库或针对特定CPU的手写汇编代码。然而,我坚信编译器优化才是解决这个问题的最佳途径和未来方向。我的坚定信念得到了老板的支持,我们顺利推动了这个项目,最终取得了很好的落地效果。现今,TVM、GLOW、MLIR等框架已成为业界认可的编译优化深度学习推理引擎。

我选择TVM作为基础框架,原因在于它在编译优化领域与我的想法最为契合。尽管TVM在18年初并不成熟,但相比其他框架,它更加接近我的技术理想。虽然没有从零开始开发,但我认为基于已有的成熟框架进行扩展,可以更快地解决问题,同时也节省了大量时间和资源。

做深度学习推理引擎,并非易事。一方面,它涉及矩阵计算的优化,这需要对编译器、体系结构、高性能计算等领域有深刻理解。另一方面,它并非想象中那么简单,深度学习推理引擎的真正实现需要下足功夫,并涵盖量化压缩、图优化、子图分离、异构执行等多个方面。例如,在支持Hexagon DSP时,深入了解其体系结构与编程模型是关键。

对于深度学习推理引擎,接收模型是第一步,包括TensorFlow、TFLite、MXNet等。目前,这一环节在不同框架中都存在不足,模型支持程度参差不齐。以TVM为例,虽然已实现了部分算子支持,但仍有大量算子未覆盖。对于开发者而言,可选择在框架基础上进行扩展,共同推动技术进步。

在解析模型后的计算图阶段,各框架实施的优化策略不尽相同,但普遍会涉及算子融合等通用优化技术。TVM引入了类似LLVM的Pass机制,支持异构执行,但在自动化的异构子图分离方面仍有改进空间。业界对于此问题的研究,包括基于传统机器学习的Cost Model与强化学习的方法,为解决异构执行问题提供了新的思路。

计算图对接外部推理引擎是另一个值得关注的点。在实际应用中,业务部门通常追求模型快速且高效执行。以GPU为例,TensorRT提供高性能推理能力,但可能不支持某些算子。结合TVM与TensorRT,通过子图分离实现不同算子在不同硬件上的高效执行,是解决这一问题的有效途径。这一策略同样适用于NPU的支持,通过异构执行达到性能优化。

在算子层面,卷积操作是优化的重点。编译器、体系结构和高性能计算领域的专家在这方面能发挥关键作用。TVM的Auto TVM和Halide思想的应用,使得优化技术的移植和性能提升变得更为高效。编译生成部分,TVM采用LLVM为基础,简化了代码指令生成的工作量,同时提供了Tensorize机制,允许开发者自定义优化。

量化压缩是深度学习领域的重要技术之一,TVM支持不同的量化策略,包括TFLite转换和TensorRT量化。量化策略的选择和优化是关键,业界的一些框架提供快速重训练等工具,以提高模型准确度和执行效率。这方面的学习和实践对于深度学习编译器的发展具有重要意义。

总之,基于编译优化的深度学习推理引擎是未来趋势,而TVM等框架在这一领域展现出巨大潜力。随着技术的不断发展,我们可以期待更多创新和突破,为深度学习应用提供更高效、更灵活的解决方案。

阅读全文

与做编译器优化有前途吗相关的资料

热点内容
代理服务器有什么功效 浏览:755
我是华为手机快手app在哪里找 浏览:812
日语中的命令行介绍 浏览:939
中央编译局比较政治学 浏览:543
管道计算app中公式如何看到 浏览:864
pythonsocket下载 浏览:822
查看所有进程的命令 浏览:3
数码摄影圣经pdf 浏览:787
苹果耳机照片怎么加密 浏览:653
电脑保存命令 浏览:786
怎么安装苏宁推客app 浏览:389
田英章7000常用字pdf 浏览:358
python爬虫起点 浏览:403
三维图常见命令 浏览:677
美的压缩机保修几年 浏览:136
linuxnfs服务器配置 浏览:85
加载算法模版失败怎么回事 浏览:374
华为手机里面的视频如何加密 浏览:215
mba教材pdf 浏览:112
安卓台服英雄联盟手游怎么更新 浏览:238