IBM JVM for Linux JIT 诊断简介(3)
- UID
- 1066743
|
IBM JVM for Linux JIT 诊断简介(3)
处理与 JIT 有关的问题通常,与 JIT 有关的问题会将一个服务调用授权给一个适当的 IBM 支持组件。JIT 诊断可能是一个非常耗时的过程,需要高级的专门技术。通常,没有定义好的算法来解决与 JIT 有关的问题,因为 JIT 具有先天的复杂性和动态特性,因此最好是在 JIT 调试过程中有一个有经验的服务代表进行指导。然而,在与 IBM 的服务部门进行联系之前,最好能确定问题是真正与 JIT 有关的。因为事实是,程序在使用 JAVA_COMPILER=NONE 时运行得很好,并不能明确地说明 JIT 就是问题的根源。在有些基准测试的情况下,完全禁用了 JIT 的版本(JAVA_COMPILER=NONE)的速度会比标准的启用了 JIT 的运行速度慢 8 倍多。在生产环境中这是不可接受的。因此,最好是具有一个产品系统的克隆副本,然后在这个系统上进行测试和调试。IBM 服务代表可以提供丰富的有关 JIT 调试的文档,以及与特定的 JIT 问题有关的说明。
本节并不是对 JIT 诊断的一份详尽的指南,而是简要介绍了可以改善 JIT 调试的基本技术,从而实现以下目标:
- 在联系 IBM 的技术支持之前,确认问题是真正与 JIT 有关的。
- 寻找一个解决方案用于两个目的:
- 提供一个暂时的解决方案,它可以在生产环境中提供可以接受的性能,同时让 IBM 修正问题的根源。
- 帮助 IBM 进行问题分析。
- 获取 IBM 技术支持判断 JIT 问题所需要的信息。
如果您不能在一段可以接受的时间内解决问题,或者如果问题对于生产来说是非常关键的,或者您早已有一个简单的测试用例可以反复重现这个问题,那就请立即与 IBM 的技术服务部门联系。
在着手进行 JIT 调试之前,首先需要确保问题是在打过最新补丁的 JVM(例如 JVM 1.3.1)上发生的,或者是在一个应用了最新的修正包的更新版本的 JVM(例如 JVM 1.4.2)上发生的,它可以为应用程序提供与之后版本的 JVM 的兼容性。
没有必要花费太多的努力在 JIT 调试上,这可能会耗费大量的时间(取决于特定情况的复杂性),最终可能是由于 JIT 的一个小问题,而这个问题可能已经在相同版本的 JVM 的一个最新的修正包中解决了。JIT 一直处于不断的更新之中,您所碰到的问题很可能早已在最新的修正包中解决了。
其次,如果问题是在完全禁用 JIT(JAVA_COMPILER=NONE)的多处理器系统上发生的,那么看一下这个问题是否也会在禁用 JIT 的单处理器平台上存在,这是非常有用的。如果这个问题不会在禁用 JIT 的单处理器上发生,那么这就可能说明 JIT 不是问题的根源。如果这个问题即使在启用了 JIT 的单处理器系统上也不会出现,那么这个问题很可能与 JIT 无关,而是与应用程序中的时间相关逻辑有关。在使用 IBM 的技术服务请求时,需要将这些信息提供给 IBM 的技术服务部门。
要了解 Linux 系统上有多少处理器以及这些处理器有哪些特性,请执行下面的命令:
JIT 调试有 3 个主要步骤。采用这三个步骤,才能获得一个性能可接受的可用解决方案,这对于 IBM 技术支持部门分析问题的根源也是非常重要的:
- 隔离产生问题的包/类/方法,在对代码进行优化或使用 JIT 编译为机器代码时,跳过 JIT 编译对代码进行编译的步骤。目标是尽可能缩小导致 JIT 问题发生的方法的范围。
隔离 JIT 问题,从而缩小方法的范围,最好能将问题定位在一个方法上。如果只调用了一个方法,就很容易给出一个不会对应用程序性能产生很大影响的解决方案,这可以让 IBM 的技术支持部门更精确地分析在进行 JIT 编译时导致问题产生的 Java 代码。
- 隔离 JIT 优化选项,将 JIT 优化选项限制为尽可能少,而且在对上面确定的方法进行错误优化的 JIT 优化层次中尽可能具体,对这些方法禁用这些优化选项。JIT 的优化选项越具体(这可以缩小范围),禁用这种优化选项产生的性能影响就越小,这样就可能会很容易得到一个解决方案。
- 这样,JIT 调试过程就会确定应用程序可能产生问题的方法的最小集合,并为产生问题的 JIT 优化选项在 JIT 优化层次中尽可能深入地定位(缩小优化选项的范围)。结合使用这两种方法,即对所涉及的方法的已经确定的有限集合禁用一些特定的优化选项(或限制优化选项的范围);或者只使用一种方法(如果只涉及一个方法的代码),就可以产生一个解决方案,其性能影响可能会很小,通常可以忽略不计。
寻找解决方案时,在付出的努力上应该有一个平衡。在 JIT 调试过程中,在某一个特定的平衡点上可以找到一个性能可接受的解决方案。如果目标只是找到一个性能可接受的快速解决方案,那么调试努力就可以到此处结束了。
然而,如果已经使用了 IBM 的技术支持的服务请求,假设没有将所涉及的方法和 JIT 优化选项的范围定位到最窄的范围,就可能会使问题的解决方案变得复杂。在这种情况下,提供一个不包含所有者机密源代码的简单测试用例,使 IBM 技术支持部门可以重现这个问题,这会是最好的方法。采用一个可以一直重现问题的简单测试用例通常都是个好主意,因为这可以显著地加速解决问题的过程。
在寻找错误的 JIT 优化机制之前,应该先定位在进行 JIT 优化时引起问题的一个方法或一组有限的方法集合。
快速解决方案过程如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 1.1 设置 JITC_COMPILEOPT=NBUILTIN:NCHA:NMMI2JIT
/* if NBUILTIN:NCHA:NMMI2JIT passes */
1.1.1 设置 JITC_COMPILEOPT=NMMI2JIT...禁用动态热点 JITC 编译
1.1.2 设置 JITC_COMPILEOPT=NBUILTIN...禁用内置的预编译的方法
1.1.3 设置 JITC_COMPILEOPT=NCHA...禁用类相互关系的分析
1.2 设置 JITC_COMPILEOPT=NINLINING...禁用内联方法
1.3 设置 JITC_COMPILEOPT=NQOPTIMIZE...禁用中间码优化
/* if NQOPTIMIZE passes then try the options below */
1.3.1 设置 JITC_COMPILEOPT=NQCOPYPROPA...禁用拷贝传播
1.3.2 设置 JITC_COMPILEOPT=NQCOMMONING...禁用高级通用措施
1.3.3 设置 JITC_COMPILEOPT=NQDEADSTORE...禁用死锁存储文件删除功能
1.4 设置 JITC_COMPILEOPT=NPRIVATIZE...禁用线程安全对象的本地化
/* New options for JVM 1.4.0 and later */
1.5 设置 JITC_COMPILEOPT=NOTHER
1.6 设置 JITC_COMPILEOPT=GLOBAL
|
我们可以将上面的过程看作是一段伪代码。将同一个 JITC_COMPILEOPT 变量逐一设置为不同的值,每次设置之后重新运行应用程序,从而确认问题是否依然存在。只有在上一个“if”条件满足时,您才需要执行缩进的操作,然后执行同一个缩进级别上的操作,直到有一个选项能允许程序毫无问题地成功运行为止。
例如,如果 JITC_COMPILEOPT=NALL 的设置不能解决问题,您就要继续执行后面的过程,否则就继续执行 1.1,然后如果通过了,就执行深一层的步骤,否则就直接跳到同一层的下一个步骤,直到问题得到解决或已经尝试完所有的选项为止。
实际上 JIT 优化选项比上面的步骤中列出的要多。例如,设置 JITC_COMPILEOPT=NALL 可以禁用除基本优化之外的大部分优化选项,包括大部分其他优化选项。也就是说,这是进行其他优化的祖先;设置 JITC_COMPILEOPT=NALL 意味着所有其他 JIT 特有的优化组件也被禁用了。
要查看 JVM 1.4.2 中 JIT 优化选项的完整列表,请设置 JITC_COMPILEOPT=TITLE(all) ,并执行一个简单的 Java 代码,例如经典的“Hello World”。
在大部分 shell 特有通用字符中,例如:
1
| " ' ` $ & | ; ( ) * ? \ > <
|
需要在前面加上转义字符“\”。
您还可以简单地将整个字符串放到单引号(')中,但是需要在变量中真正的单引号字符前面加上一个反斜线(\')。
JVM 1.4.x JIT 选项及其内部层次关系的详细列表可以打印出来。这个列表可以用来将问题的范围限制在引起问题的一个优化选项(或者一个优化选项的小集合)上。
如果您需要将当前的设置打印到标准输出上,JITC_COMPILEOPT=TITLE 选项也会非常有用。这可以帮助确保您考虑的正在设置的选项实际上都正被 JIT 编译器接受和识别。
要减少错误发生所需要的时间,您可能会希望如下的设置:IBM_MIXED_MODE_THRESHOLD=0。这样会禁用 MMI,并且每个方法都是在第一次碰到时进行编译,这样,问题就可能早些浮现出来。当然,禁用 MMI 会强制所有的方法都在首次碰到时进行编译,这样就会编译很多不是热点方法且只会被调用很少次数的方法。由于采用这种方法所引起的编译负载可能会实际增加程序运行到出现问题的地方所需要的时间。您可能会希望试验大量的值来找到一个可以快速引起问题的值。
设置 JITC_COMPILEOPT 变量来禁用特定的 JIT 优化选项,而不用指定要禁用哪个包、类或方法,这意味着会对应用程序的所有代码都禁用这些优化选项,从而会在整个程序的范围产生性能的影响。这就是为什么上面这个过程只是给出一个快速解决方案的建议。主要的压力应该在于隔离在进行 JIT 编译时引起问题的方法或方法集。 |
|
|
|
|
|