高性能应用中,C/C++与Java/C#相比较。

11
我的问题是关于Java与编译代码(例如C++/Fortran/汇编语言)在高性能数值应用程序中的表现。其中双精度矩阵乘法,在blas库中通常称为dgemm,能够实现接近100%的CPU峰值性能(以每秒浮点运算次数表示)。有几个因素可以实现这种性能:缓存分块以实现最大内存局部性、循环展开以最小化控制开销、矢量指令(如SSE)、内存预取和确保没有内存别名。我看到了许多使用汇编、C++、Fortran、Atlas、供应商BLAS的基准测试(典型情况是512及以上维度的矩阵)。另一方面,我听说像Java这样的原则字节编译语言/实现可以快速或几乎与机器编译语言一样快。然而,我没有看到明确的基准测试结果表明它是这样的。相反,从我自己的研究来看,字节编译语言要慢得多。您是否有好的Java/C#矩阵乘法基准测试?即时编译器(实际实现,而不是假设)能否生成满足我列出的点的指令?每个CPU都有峰值性能,这取决于处理器每秒可以执行的指令数。例如,现代2 GHz英特尔CPU可以实现每秒8亿个双精度加/乘,从而产生8 gflops的峰值性能。矩阵乘法是能够实现几乎完整性能的算法之一,其主要原因是计算与内存操作的比率更高(N³/N²)。我感兴趣的数字在N>500左右。

关于实现方面:高层次的细节,如阻塞,在源代码级别上完成。低层优化由编译器处理,可能使用有关对齐/别名的编译器提示。字节编译实现也可以使用阻塞方法编写,因此原则上良好实现的源代码细节将非常相似。


我可以编写Java代码,即使没有做任何有意义的事情,也可以利用100%的CPU。我猜我明白你真正的意思,但你的措辞有点含糊不清。 - Péter Török
对我来说还不是很清楚...你的意思是存在某种“理想状态”,即对于给定的CPU架构,最佳的数值性能是如此,这就是你所说的100%吗?是否会有一些具体的度量标准,例如MFLOPS?我不是这个领域的专家。 - Péter Török
我没有投票关闭这篇帖子(甚至还没有权利)。我觉得它很有趣,只是想给你反馈以澄清你的帖子。 - Péter Török
你能选择一个矩阵大小或几个矩阵大小来使问题更具体吗? - President James K. Polk
@peter。你好,我不是想让结束语针对你,很抱歉。我会再澄清一下。 - Anycorn
@GregS 我对大小进行了一些澄清。 - Anycorn
5个回答

2
在一个纯矩阵乘法场景中,VC++/.NET 3.5/Mono 2.2的比较:
Mono配合Mono.Simd可以大大缩小与手动优化的C++之间的性能差距,但C++版本仍然明显是最快的。不过现在Mono已经更新到了2.6,性能可能更接近了,而且如果.NET也像Mono.Simd一样有这样的东西,它也可能非常有竞争力,因为.NET和这里的顺序C++之间几乎没有什么区别。

谢谢。两个SIMD实现之间的差异是什么?看一下数据,似乎与内存有关? - Anycorn
1
说到C++中的SSE,我建议你也比较一下GCC 4.4,以保证完整性,因为MSVC的SSE代码生成真的很糟糕(详见http://www.liranuna.com/sse-intrinsics-optimizations-in-popular-compilers/)。 - LiraNuna

1
您指定的所有因素可能都是通过手动内存/代码优化来完成特定任务的。但 JIT 编译器没有足够的关于您领域的信息,无法像手动优化一样使代码最优,并且只能应用一般的优化规则。结果将比 C/C++ 矩阵操作代码慢(但如果需要,可以利用 100% 的 CPU :))。

返回翻译后的文本: true。但是向量化和别名问题通常由编译器处理。此外,我期望编译器进行循环展开。在编译语言中,缓存访问非常简单明了,但是字节编译语言如何处理它呢? - Anycorn
@aaa:JIT 引擎/编译器会处理这个问题。 - LiraNuna

0
在一个纯数学场景中(计算25种代数表面的3D坐标),C++比Java快2.5倍。

0

Java在矩阵乘法方面无法与C相比,其中一个原因是它会在每次访问数组时检查是否超出了数组边界。此外,Java的数学计算速度较慢,它不使用处理器的sin(),cos()函数。


0

2
据我所知,它不使用SSE指令来向量化代码,.NET CLR也不是。Mono确实有一些结构体(向量和矩阵),这些结构体被JIT编译器特殊处理并转换为向量化代码。 - JulianR
@JR 这也是我的印象 - Anycorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接