jnafortran性能调优
我正在使用JNA包装本机代码(主要是Fortran 77)。本机函数的输出(即结果)由一组嵌套(自定义)类型/结构组成,我将这些类型/结构映射到JNA中相应的jnafortran性能调优,fortran,jna,Fortran,Jna,我正在使用JNA包装本机代码(主要是Fortran 77)。本机函数的输出(即结果)由一组嵌套(自定义)类型/结构组成,我将这些类型/结构映射到JNA中相应的Structure。这些结构主要由其他结构的数组组成(因此结构A包含结构B的数组,结构B包含结构C的数组等) 使用相同的基准测试(主要是记录时间差异),我发现大部分时间不是花在本机代码上,而是花在JNA映射上。Fortran子程序调用大约需要50毫秒,但总时间是250毫秒 我发现了 .setAutoWrite(false)在我们的结构上将
Structure
。这些结构
主要由其他结构的数组组成(因此结构A包含结构B的数组,结构B包含结构C的数组等)
使用相同的基准测试(主要是记录时间差异),我发现大部分时间不是花在本机代码上,而是花在JNA映射上。Fortran子程序调用大约需要50毫秒,但总时间是250毫秒
我发现了
.setAutoWrite(false)
在我们的结构上
将开销减少约2倍(总执行时间几乎减半)
- 保持(静态分配的)数组尽可能小有助于降低JNA开销
- 将
双精度
(双精度
)更改为实数
(浮点
)似乎没有任何区别
在我们的例子中,有没有进一步的技巧来优化JNA性能?我知道我可以将我的结构扁平化为一个1D基元数组并使用直接映射,但我尽量避免这种情况(因为对这些结构进行编码/解码将是一件痛苦的事情)如中所述,直接映射将是您最佳的性能提升,但您已将其作为选项排除在外。它还注意到,每个本机调用的调用开销是另一个性能问题,您已经通过更改setAutoWrite()
部分解决了这一问题
您还提到将结构扁平化为一组基本体,但由于编码/解码的复杂性,您拒绝了这一点。然而,朝这个方向发展可能是下一个最佳选择,而且您目前面临的最大性能问题可能是JNA的结构
使用反射和本机读取进行访问的组合
因为反射涉及动态解析的类型,
无法执行某些Java虚拟机优化。
因此,反射操作的性能比其
非反射副本,并且应在代码部分避免使用
在性能敏感的应用程序中经常调用
因为您在这里提出了一个与性能相关的问题,并且使用了JNA结构,所以我只能假设您正在编写一个“性能敏感的应用程序”。在内部,该结构执行以下操作:
for (StructField structField : fields().values()) {
readField(structField);
}
它对每个字段执行一个本地读取,然后执行此操作,最后使用引擎盖下的反射
setFieldValue(structField.field, result, true);
这个故事的寓意是,通常在结构中,每个字段都涉及本机读+反射写,或者反射读+本机写
您可以在不做任何其他更改的情况下执行的第一步是对结构进行修改。(您已经在“写入”版本中完成了一半;它同时执行读取和写入操作。)从文档:
对于非常大或复杂的结构,您只需要
访问少量字段,您可能会看到显著的性能
避免自动结构读写的好处。如果自动读取
如果禁用了and-write,则由您来确保Java
感兴趣的字段在本机函数调用前后同步
通过readField(字符串)和writeField(字符串,对象)。这通常是
当本机调用填充大型结构且您
只需要几个字段。在本机呼叫后,您可以呼叫
仅在感兴趣的字段上读取字段(字符串)
为了真正全力以赴,平坦化可能会稍微有助于消除任何反射开销。诀窍是使偏移量转换变得容易
平衡复杂性和性能的一些方向:
- 要写入本机内存,请分配并清除字节缓冲区(
mem=new memory(size);mem.clear();
或仅new byte[size]
),并将特定字段写入使用Structure.fieldOffset(name)
中的值确定的字节偏移量。这确实使用反射,但您可以对每个结构执行一次反射,并存储一个名称映射以供以后使用
- 对于从本机内存读取,请使用平面缓冲区进行所有本机读取调用,以将本机开销减少到单个读取/写入。您可以在读取该缓冲区时将其强制转换为结构(对每个字段进行一次反射),或者按照上述策略读取特定的字节偏移量
只要说Fortran是否返回“structs”,不管它是什么,肯定不会Fortran77@IanBush我说的“大部分”是Fortran 77,有些部分作为用户定义类型(Fortran 90)更新