通过 JNI 将两个数组从 java 传递到 c++ 时,使用 c++ 内在函数(或 asm-inline)来提高性能存在三个障碍。
1)JNI调用有开销(如预期,20个周期到100个周期)
2)数组作为未对齐传递(需要 32B 或 16B 对齐),因此需要移动整个两个数组以使它们对齐,然后最后移回旧位置。
3)创建一个新数组将结果发送到java(例如:向量乘法C=A*B)如果我们从java提供一个数组,它也会错位!所以我们需要在 C++ 中创建一个新的对齐数组,这会减慢整个过程。
我们可以制作一个更大的数组来连接两个数组,而不是移动两个数组,但这也会很慢。
如果我们只能使用(更少数据,更多计算)结构,那么使用 JNI 来提高性能有什么意义?
——在 JNI 中使用纯 c++(无内在)只比纯 java 快 %10-%20。
--使用内在函数将乘法/秒增加了 %70,但缓慢的数组复制仍然有效。java 将其数组移动到 32B 对齐位置的几率只有 %50。
GetPrimitiveArrayCritical
-- 使用而不是给大向量( 256kGetArrayElements()
个元素)的点积带来另一个 %250 的性能。这一定是在 JNI 工作和非复制访问时关闭 gc-down 的结果。
--在我的机器上使用直接字节缓冲区而不是原始数组是 %40(纯 java 之上的 5x-6x) 更快。还可以让我在本机地址选择器的帮助下选择一个自定义偏移量,使其与 32B 对齐。所以我们可以有一个直接缓冲区的 32B 对齐子集(在“C”空间中),但不是一个原始数组。
-- 将一个大缓冲区分成 8 个部分和 8 个 java 线程,与单个 directbytebuffer 相比,计算速度再快 40%(这可能接近我的内存的限制,因为我每个元素只做一次乘法)
最新案例与 java 的单线程循环展开乘法的总速度比接近 6 倍,在我应用多线程之后,对于这个特定的点积,它增加到 8 倍(不是因为内存带宽,而不是计算限制)。
您可以添加什么来克服上述三个困难?
我们如何通过 JNI 将 32B 对齐的数组从 java 传递到 c++?