Java 自动矢量化

Java autovectorization

我想了解 JDK 何时会自动向量化。我有以下一组问题(尽管使用谷歌搜索、阅读、实验等)。给定一个简单的循环如下:

for(int i=0; size = size(); i < size; i++) {
   a[i] = b[i] * c[i];
   method1();
   // someObject.method2();
   // someHashMap.put(b[i], c[i]);
}
  1. 为什么需要内联方法调用 "method1"(出现在循环中)以进行自动矢量化? (我不明白为什么 必须 是必要的....)
  2. 也许这是一个 "silly" 问题,但如果 "someObject.method2()" 没有注释呢? (并且假设 method2 是一个巨大的方法,即很多行)。这也会阻止自动向量化吗?如果 method2 是一个很小的方法(例如只有 1 或 2 行等?)
  3. 如果取消注释 "someHashMap" 行会怎样?我们有一个将在所有 SIMD 之间共享的 object/variable 这一事实是否也会导致自动矢量化失败? (我看不出它是如何工作的,除非 jdk 在访问 "someHashMap"
  4. 的公共 object/var 时以某种方式自动插入 "syncronization" 关键字
  5. 在我看来,"streaming" 接口可以解决上面问题 #3 中隐含的问题,因为流中的 "collector" 逻辑会自动处理合并各个 hashmap,因此我们不需要任何 "synchronized" 字。 (总的来说,只要没有 "outside vars"(即没有副作用)在创建流式代码时...当使用标准流式接口编写代码时,jdk/jit 编译器会自动执行自动矢量化吗?如果没有,这样做是否有意义(也许在未来的 jdk 版本或者来自其他供应商的 jdk 版本?)
  6. 如果循环体包含很多很多 if 语句等(很多分支,让我们进一步说每个分支做很多计算),这是否意味着 a) 自动矢量化可能是一个坏主意(就像它一样将用于 GPU) 和 b) jit 编译器足够聪明,可以确定自动矢量化是一个坏主意,因此它不会自动矢量化?
  7. 我目前正在使用 Oracle jdk8,但是如果使用 jdk9 或 jdk10 等,上面的答案会改变吗?

为了回答您的问题 (1),原则上,Java 编译器可以在存在非内联 method1() 调用的情况下进行优化,if 它分析了 method1() 并确定它没有任何会影响自动矢量化的副作用。特别是,编译器可以证明该方法是 "const"(没有副作用,也没有从全局内存中读取),这通常会在调用站点启用许多优化而无需内联。它还可能证明更受限制的属性,例如不读取或写入特定类型的数组,这也足以允许在这种情况下进行自动矢量化。

在实践中,但是,我不知道现在有任何 Java 编译器可以进行这种优化。如果相信 ,在 Hotspot 中:"a [not-inlined] method call is typically opaque for JIT compiler." 大多数 Java 编译器都以某种方式基于 Hotspot,所以我不希望有一个复杂的 Java 编译器可以在 Hotspot 不能的情况下做到这一点。

这个答案还涵盖了为什么这样的过程间分析 (IPA) 可能既困难又不是特别有用的一些原因。特别是,关于可以证明非平凡事物的方法通常足够小,以至于它们无论如何都会被内联。我不确定我是否完全同意:有人还可以争辩说 Java 部分积极地内联 因为 它不执行 IPA,所以强大的 IPA 可能会打开能力减少内联,从而减少运行时代码占用空间和 JIT 时间。

您在 (2) 或 (3) 中询问的其他方法变体没有任何改变:编译器仍然需要 IPA 并允许它进行矢量化,据我所知 Java 编译器没有。

(4) 和 (5) 似乎应该作为完全不同的问题提出。

关于 (6) 我认为它没有改变,但它会成为 OpenJDK 热点邮件列表的一个很好的问题:我认为你会得到一个很好的答案。

最后,值得注意的是,即使没有 IPA 并且对 method1() 一无所知,编译器也可以优化 ab 和 [=15= 上的数学运算] 如果能证明有none人逃脱了。不过,这在一般情况下似乎毫无用处:这意味着所有这些变量都将在此函数中分配(或内联到该函数中的某个函数),而我想在大多数现实情况下,至少传递了三个中的一个来电者。