一种基于学习的Java虚拟机性能优化方法
未命名
08-15
阅读:120
评论:0
一种基于学习的java虚拟机性能优化方法
技术领域
1.本发明属于计算机编译器技术领域,具体涉及语言虚拟机的运行时优化方法。
背景技术:
2.及时编译器(just-in-time compiler,jit)为了实现可移植性,它使用字节码作为隐藏硬件细节的中间表示,以在不同平台上的jvm执行。jvm的执行引擎是由解释器和及时编译器(jit)的组合,字节码在进入jvm时会首先被解释器执行,并同时被监测代码的执行频率。当一些代码的执行频率达到足够高,并触发阈值成为热点代码时,jit会介入对字节码进行分析、优化,编译生成更高效的本地代码。
3.传统jvm执行引擎的设计存在着解释器与编译器协同低效的问题。解释器虽然能够快速提供对字节码的翻译,但是它逐条且不做优化的翻译质量较低。另一方面,编译器虽然能够生成高效的本地代码,但是它的分析、优化过程非常耗时,翻译速度很慢。因此,编译器的优化范围仅限于执行多次的热点代码,进而导致了相当一部分代码将会在低翻译质量状态执行的性能问题。
4.解释器和编译器的低效协同的背后是它们无法在翻译速度和翻译质量上做出很好的权衡。许多运行时的优化需要经过ir构建、全局分析等较为耗时的过程,如果花费这些开销生成的高效代码不能被多次执行,相比于解释器产生足够多的提升收益,那么整体来看这些运行时优化就不能够带来性能提升。因此,此类优化不适合大范围被应用到所有的代码,而仅限于执行次数足够多的热点代码。
5.当前针对java虚拟机(java virtual machine,jvm)的性能优化的技术有两类:一类是通过测试运行结果来指导修改虚拟机配置参数,其中包括高赫提出了基于压力测试结果来修改jvm配置参数的方法(cn103186412a),胡阳辉提出了通过运行时堆的性能数据来修改gc中新生代、老年代等配置参数的方法(cn110888712a),李强提出了基于垃圾回收时间比较来修改配置参数的方法(cn105824687b)。另一类是通过修改jvm本身,例如张国磊提出了一种基于simd提高jvm性能的方法(cn115421849a),通过向jvm中加入simd指令来提高执行效率。
6.本发明不同于现有方法,是对jvm翻译机制进行新的设计,通过在执行架构中引入基于学习的方法来提高翻译效率,从虚拟机内部出发来解决一些本源的性能问题,而不是从虚拟机外部出发去修改配置参数,本发明方法独特且方便易用。另外,本发明翻译效率的提升对jvm的运行性能带来了提升,且不依赖于某一特定硬件资源,如平台需要支持simd指令集,本发明适用范围更加广泛。
7.本发明提出一种基于学习的方法,从jit生成的优化代码中获取优化知识。通过构建从字节码到jit优化代码之间的关系并转化为翻译规则,进一步应用到基于规则的翻译器当中,做到快速生成高质量翻译代码,最终实现可以提前介入对所有范围内代码进行优化的目标,以解决上文提到的传统jvm所存在的性能问题。
技术实现要素:
8.本发明的目的在于提供一种翻译效率高、适用范围广的java虚拟机性能优化方法。
9.本发明提供的java虚拟机性能优化方法,是基于学习技术的;通过在java虚拟机执行架构中引入学习的方法来提高翻译效率,从虚拟机内部出发来解决一些本源的性能问题,而不是从虚拟机外部出发去修改配置参数;本发明通过学习及时编译器(jit)中的优化知识,建立从字节码到优化后代码的对应关系,构建基于规则的翻译器;本发明优化方法主要分为两个阶段,分别是学习阶段和应用阶段,参见图1所示。其中:
10.(一)学习阶段,具体步骤为:
11.步骤1,规则学习;通过扩展jit来实现,使其生成能够辅助代码匹配的调试信息,如图2所示;其中,一个调试信息是代码行号,用于将本地代码和生成它们的字节码关联起来;jit以函数为单位进行编译,在通过行号关联后得到若干段字节码-本地代码对;另一个调试信息是操作数映射;由于字节码是一种栈式指令集,而本地代码如x86、arm一般是寄存器式指令集;因此,二者之间存在较大的语义隔阂;具体体现在栈式指令集的操作数是隐含于操作数栈中的,如图4中的左侧表格所展示的字节码,其中iadd指令是从栈上弹出两个操作数进行运算,这两个操作数是由前面的两条iload_0、iload_1指令提供的,而iadd指令本身不包含任何操作数相关的信息,因此称之为“隐式操作数”;而本地代码的操作数是显式的;为了克服此语义隔阂,本方法扩展jit,使其能够构建隐式操作数和显式操作数之间的对应关系(即字节码与本地代码之间的对应关系);最终学习此对应关系来构建翻译规则。
12.步骤2,参数化;由于机器学习的效果受限于训练集,为了提高学到的翻译规则的覆盖率,降低训练集的大小,本发明对翻译规则进行参数化;经过对字节码和本地代码的观察,有如下发现:二者的操作符存在相似性,例如字节码的加法操作符(iadd)和异或操作符(ixor),对应本地代码的加法操作符(addl)和异或操作符(xorl),都是对两个源操作数进行计算,然后存回目标操作数;通过这个发现,可以将已学到的翻译规则中带有的iadd参数化为一个通用操作符op2,用于翻译ixor等其他类似的二元运算符;这样的参数化能使翻译规则适用到更多的场景,有效提高规则的覆盖率。
13.步骤3,语义验证;虽然翻译规则经过步骤1关联到源于同一源码所对应的字节码与本地代码,但是jit在其中做出的转换过程还是可能导致二者存在语义上的差距;例如图3所示的存在问题的翻译规则;在字节码端只有操作数v2被iadd写入了新的值,但是本地代码端的r1,r2都被新的值所覆盖了,这样的规则是不能够应用到翻译中的;因此,本发明采用符号执行技术对问题规则进行筛查、验证,保证应用到翻译中的规则的正确性。
14.(二)应用阶段,具体步骤为:
15.步骤1,规则应用;首先通过一个虚拟的操作数栈来模拟字节码的执行过程,克服字节码和本地代码之间存在语义隔阂,将字节码的隐式栈操作数转化为显式的操作数,如局部变量表的某一项,或某一条运算字节码的结果,大致流程如图4所示;在此步骤的操作后,相应的操作字节码会带有具体的操作数,以便翻译规则的应用;随后,根据操作符选择相应的翻译规则,生成相应的本地代码。
16.步骤2,寄存器分配;为了避免像解释器一样过度使用内存导致性能下降,本发明使用一个轻量级的基于栈的寄存器分配器;其算法大致如下:将空闲寄存器放入一个池中
进行管理;在栈消除过程中,当一个变量被压入操作数栈时,从池中为之分配一个寄存器;当一个操作符到来时,它弹出的几个变量将释放它们的寄存器,除了堆栈顶部的一个变量,如果必要的话,它的寄存器将用于存储新的结果;在池中没有空闲寄存器的情况下,堆栈中最深的变量将溢出到内存中,因为它是最后被使用到的。
17.步骤3,代码生成;在规则应用和寄存器分配之后,规则中的操作码和操作数就可以实例化了,因为我们已将它们泛化为抽象的操作码和操作数;这里应用了一种优化方法,直接在指令中插入值,而不是引入辅助移动指令;有两种类型的操作数可以优化,常量或局部变量;对于常量,如果指令具有使用即时操作数的寻址模式,如x86中的addl,可以在指令中使用整型常量的值;对于局部变量,如果它们存储在方法参数寄存器中,直接将寄存器使用到指令操作数中;通过规则中的分支指令构造转换的控制流,并在指令中填充目标地址。
18.本发明方法能够实现快速地生成高质量代码的目标,不需要等待解释器以低效状态执行足够多次数之后,再由jit介入对代码质量进行优化。因此,本方法从本源上解决了jvm执行引擎存在的性能瓶颈。此外,本方法使用的参数化技术,使得以较小的程序集作为输入,就能够生成高覆盖率的翻译规则。
附图说明
19.图1为本发明方法流程图。
20.图2为本发明的规则学习示意图。
21.图3为本发明的语义验证中将被排除的错误翻译规则示意图。
22.图4为本发明的规则应用阶段的栈消除示意图。
具体实施方式
23.根据本发明,需要实施的内容主要分为是学习阶段和应用阶段。
24.学习阶段的实现由两部分组成。一部分是对jit和反汇编程序的实现扩展,集成在jvm源代码中(openjdk11中的hotspot jvm,用c++编写),让它们生成本地代码和所需的调试信息(大约数百行代码)。另一部分是jvm之外的程序。它负责解析jit生成的学习资源,并将符号执行字节码转换为vine ir进行验证。它是用python脚本(约5.2k代码行)和fuzzball框架以及我们添加的ocaml包装器代码(约3.6k代码行)实现的。
25.应用阶段的实现实际上是翻译器的代码。它也集成在jvm中,包括大约8.6k行c++代码。我们的设计理念是将解释器和hotspot c1合并在一起。可翻译方法中的字节码将直接交给基于学习的翻译器,而不是解释器。当翻译器生成的代码成为热点时,c2将重新编译该方法以接受进一步的优化。该阈值与c1生成的用于涉及c2的代码所使用的阈值相同。对于不可翻译的方法,它们将遵循解释器的原始路径,然后是c1,最后是c2。
26.为了验证本方法的可行性和有效性,我们运行了基准程序集dacapo-9.12并收集了相应的实验数据。本方法相比于默认模式下的jvm能够实现1.22倍的加速比。同时,本方法加入的参数化能够使得从一个基准程序那里学来的翻译规则就能够达到98.7%翻译覆盖率。
技术特征:
1.一种基于学习的java虚拟机性能优化方法,其特征在于,在java虚拟机执行架构中引入学习的方法,通过学习及时编译器(jit)中的优化知识,建立从字节码到优化后代码的对应关系,构建基于规则的翻译器;具体分为两个阶段:学习阶段和应用阶段,其中:(一)学习阶段,具体步骤为:步骤1,规则学习;通过扩展jit来实现,使jit生成能够辅助代码匹配的调试信息;其中,一个调试信息是代码行号,用于将本地代码和生成它们的字节码关联起来;jit以函数为单位进行编译,在通过行号关联后得到若干段字节码-本地代码对;另一个调试信息是操作数映射;由于字节码是一种栈式指令集,而本地代码是寄存器式指令集;二者之间存在较大的语义隔阂;为了克服此语义隔阂,扩展jit,构建字节码与本地代码之间的对应关系,最终学习此对应关系来构建翻译规则;步骤2,参数化;即对翻译规则进行参数化;经过对字节码和本地代码的观察,有如下发现:二者的操作符存在相似性,即字节码的加法操作符(iadd)和异或操作符(ixor),对应本地代码的加法操作符(addl)和异或操作符(xorl),都是对两个源操作数进行计算,然后存回目标操作数;根据这个发现,将已学到的翻译规则中带有的iadd参数化为一个通用操作符op2,用于翻译ixor以及其他类似的二元运算符;步骤3,语义验证;采用符号执行技术对问题规则进行筛查、验证,保证应用到翻译中的规则的正确性;(二)应用阶段,具体步骤为:步骤1,规则应用;首先通过一个虚拟的操作数栈来模拟字节码的执行过程,克服字节码和本地代码之间存在语义隔阂,将字节码的隐式栈操作数转化为显式的操作数;随后,根据操作符选择相应的翻译规则,生成相应的本地代码;步骤2,寄存器分配;使用一个轻量级的基于栈的寄存器分配器;其方法如下:将空闲寄存器放入一个池中进行管理;在栈消除过程中,当一个变量被压入操作数栈时,从池中为之分配一个寄存器;当一个操作符到来时,它弹出的几个变量将释放它们的寄存器,除了堆栈顶部的一个变量,它的寄存器将用于存储新的结果;在池中没有空闲寄存器的情况下,堆栈中最深的变量将溢出到内存中;步骤3,代码生成;使用优化方法,直接在指令中插入值,具体对如下两种类型的操作数优化:常量或局部变量;对于常量,如果指令具有使用即时操作数的寻址模式,在指令中使用整型常量的值;对于局部变量,如果它们存储在方法参数寄存器中,直接将寄存器使用到指令操作数中;通过规则中的分支指令构造转换的控制流,并在指令中填充目标地址。
技术总结
本发明属于计算机编译器技术领域,具体为一种基于学习的Java虚拟机性能优化方法。本发明方法包含学习阶段、应用阶段;学习阶段的步骤分为规则学习、参数化和语义验证,应用阶段的步骤分为规则应用、寄存器分配和代码生成。本发明通过学习的方法,从JIT生成的优化代码中获取优化知识;通过构建从字节码到JIT优化代码之间的关系并转化为翻译规则,进一步应用到基于规则的翻译器当中,做到快速生成高质量翻译代码,最终实现提前介入对所有范围内代码进行优化的目标,以解决传统JVM所存在的性能问题。本发明不是像传统设计由于编译开销的原因仅仅局限于热点代码。本发明可用于语言虚拟机上。机上。机上。
技术研发人员:张为华 王涵章 蒋金虎
受保护的技术使用者:复旦大学
技术研发日:2023.05.13
技术公布日:2023/8/14
版权声明
本文仅代表作者观点,不代表航空之家立场。
本文系作者授权航家号发表,未经原创作者书面授权,任何单位或个人不得引用、复制、转载、摘编、链接或以其他任何方式复制发表。任何单位或个人在获得书面授权使用航空之家内容时,须注明作者及来源 “航空之家”。如非法使用航空之家的部分或全部内容的,航空之家将依法追究其法律责任。(航空之家官方QQ:2926969996)
飞行汽车 https://www.autovtol.com/
