我有一些非常高性能的关键代码,通过执行一些浮点比较或简单的谓词,高层代码可以做出很多决策。 可以以决策树的形式编写代码。基本上,每个节点都会进行谓词检查,然后确定要走的路,直到到达某个叶节点为止。
为了提高性能而不是使用决策树,我生成了一些if-else代码块,这些代码块在程序运行时进行编译(基本上,因为我事先知道谓词,所以我会为整个决策树生成代码)。确实可以大大提高性能。 现在,我想做的下一个优化是在运行时修改代码,即在没有代码生成的旧世界中,并且有带有节点的决策树,我本可以复制树并在某些节点上短路/跳跃,从而压缩树使整体计算更快。但是在生成的代码世界中,是否有任何工具可以通过基于计算过程中可用的部分运行时数据修改生成的if-else代码来实现相同的功能。还有修改运行时代码的性能含义。
答案 0 :(得分:1)
首先,JVM不允许您修改正在运行的代码。它允许您执行的操作是在运行时生成新代码并加载它。
此外,还有一个Oracle赞助的项目(GraalVM),在该项目中(如果我理解正确的话),您可以生成(松露)AST,并使框架负责代码生成。 (目前,这似乎是实验性的,可能尚未准备好用于生产。)
此外,修改运行时代码的性能含义是什么。
这是65,536美元的问题!
一个暗示是,每次(通过重新生成代码)修改代码时,都必须重新加载该方法,并且(对于传统的JVM)必须再次经历解释和JIT编译阶段。并可能会对依赖于已修改代码的其他代码进行非优化/重新优化。
那不会便宜。每次您执行此操作时,我都在猜测每种方法成千上万的本机指令。
现在我要做的下一个优化是在运行时修改代码...
好。因此,我认为您最好进行更复杂的代码生成。
但是也要记住,JIT编译器将优化您生成的字节码,基于在解释方法时(在JIT编译之前)基于收集的统计信息进行分支预测等操作。
在尝试实施自己的优化器之前,我还建议您手动尝试一些优化并进行基准测试。
答案 1 :(得分:1)
这就是我将https://github.com/OpenHFT/Java-Runtime-Compiler用于
的原因例如
// dynamically you can call
String className = "mypackage.MyClass";
String javaCode = "package mypackage;\n" +
"public class MyClass implements Runnable {\n" +
" public void run() {\n" +
" System.out.println(\"Hello World\");\n" +
" }\n" +
"}\n";
Class aClass = CompilerUtils.CACHED_COMPILER.loadFromJava(className, javaCode);
Runnable runner = (Runnable) aClass.newInstance();
runner.run();
我建议使用一个不变的已知接口,您可以调用并让生成的代码实现该接口。
这不支持重新加载类,但是您可以每次生成一个新的类名,或者每次使用一个不同的类加载器。