【发布时间】:2014-05-03 22:12:43
【问题描述】:
有点相关的问题,一岁了:Do any JVM's JIT compilers generate code that uses vectorized floating point instructions?
前言:我正在尝试在纯 Java 中执行此操作(没有 JNI 到 C++,没有 GPGPU 工作等......)。我已经分析过,大部分处理时间来自此方法中的数学运算(可能是 95% 的浮点数学和 5% 的整数数学)。我已经将所有 Math.xxx() 调用减少到一个足够好的近似值,所以现在大部分数学都是浮点乘法和一些加法。
我有一些处理音频处理的代码。我一直在进行调整,并且已经获得了巨大的收益。现在我正在研究手动展开循环,看看是否有任何好处(至少手动展开 2,我看到大约 25% 的改进)。在尝试手动展开 4 时(这开始变得非常复杂,因为我正在展开嵌套循环的两个循环)我想知道是否有什么我可以做的来暗示 jvm 在运行时它可以使用向量操作(例如 SSE2、AVX 等)。音频的每个样本都可以完全独立于其他样本进行计算,这就是为什么我已经能够看到 25% 的改进(减少了对浮点计算的依赖量)。
例如,我有 4 个浮点数,循环的 4 个展开中的每一个都有一个浮点数,用于保存部分计算的值。我如何声明和使用这些花车重要吗?如果我将其设为浮点数 [4],这是否会向 jvm 暗示它们彼此无关,而不是具有浮点数、浮点数、浮点数、浮点数甚至是一类 4 个公共浮点数?有什么我可以做的毫无意义的事情会扼杀我对代码进行矢量化的机会吗?
我在网上看到过有关“正常”编写代码的文章,因为编译器/jvm 知道常见模式以及如何优化它们,而偏离这些模式可能意味着更少的优化。然而,至少在这种情况下,我不会期望将循环展开 2 来提高性能,所以我想知道是否还有其他事情可以做(或者至少 没有 em> 做)来帮助我的机会。我知道编译器/jvm 只会变得更好,所以我也想提防将来做会伤害我的事情。
为好奇编辑:展开 4 将性能提高 another 比展开 2 提高约 25%,所以我真的认为如果 jvm 支持向量操作(或者可能已经正在使用它们)。
谢谢!
【问题讨论】:
-
1.如果内循环重复多次,我认为展开外循环没有任何意义。 2. JVM 本身做了很多展开,但有时它无法利用它。 This question 在一个简单的案例中显示了近 4 倍的改进。 3. 编写清晰简单的代码在 99.9% 的情况下都是正确的,但如果您知道自己在做什么并努力并为维护成本做好准备,那么您可以做得比 JIT 更好。
-
@maaartinus 感谢您的链接。内部循环通常执行 10 到 300 次,具体取决于一些用户选择(通常在 30-40 左右的低端)。然而,外部循环被执行了数万或数十万次。我尝试只展开内部循环,但它增加了执行时间。我只尝试展开外循环,它确实减少了执行时间,但只是一点点。我想当两者都展开时,CPU 真的可以更容易地挑选出依赖链。
-
我的想法是:当内部循环执行 10 次时,它内部的每条指令的权重是外部指令的 10 倍;因此我会忽略外面。我只能猜测,但我敢打赌,JVM 无论如何都会展开(有时甚至是too much),而减速只是 JIT 故障(它以不同的方式优化两个等效块,结果时间差异很大)。恐怕查看生成的汇编程序是要走的路。
-
你明确排除了 GPGPU(我想知道为什么......),但也许你还是应该看一下 code.google.com/p/aparapi :它将使用 OpenCL 进行计算(这可以是GPU 或 CPU!),或者当没有可用的 OpenCL 时使用 Java 线程池。
-
@Marco13 我不包括 GPGPU 选项,因为虽然是的,这几乎是 GPU 工作的完美候选者,但它否定了 java 所追求的“编写一次运行任何地方”的巨大好处。我想让它在纯 java 中尽可能高性能。目标不是“我需要尽可能节省时间吗?” (或者我会用 C 语言编写它并使用 CUDA/OpenCL),但是“我怎样才能在 Java 中尽可能地提高时间效率?”我对此提出的一个问题是,是否有办法向 jvm 提示向量优化会有所帮助。不过欣赏链接!我没听说过。
标签: java performance jvm-hotspot