与Java相比,为什么此C 代码执行速度如此慢
Why is this C++ code execution so slow compared to java?
我最近在Java中编写了一种计算密集型算法,然后将其转换为C 。令我惊讶的是,C 执行速度较慢。现在,我编写了一个短得多的Java测试程序和一个相应的C 程序 - 见下文。我的原始代码和测试代码都有很多数组访问。C 执行时间需要更长的5.5倍(请参阅每个程序末尾的注释(。
1 st 21评论以下结论...
测试代码:
-
g++ -o ...
Java更快5.5倍 -
g++ -O3 -o ...
Java 2.9倍更快 -
g++ -fprofile-generate -march=native -O3 -o ...
(运行,然后是g++ -fprofile-use
等(Java 1.07倍。
我的原始项目(比测试代码复杂得多(:
- Java更快1.8倍
- C 1.9倍更快
- C 2倍
Software environment:
Ubuntu 16.04 (64 bit).
Netbeans 8.2 / jdk 8u121 (java code executed inside netbeans)
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Compilation: g++ -o cpp_test cpp_test.cpp
Java代码:
public class JavaTest {
public static void main(String[] args) {
final int ARRAY_LENGTH = 100;
final int FINISH_TRIGGER = 100000000;
int[] intArray = new int[ARRAY_LENGTH];
for (int i = 0; i < ARRAY_LENGTH; i++) intArray[i] = 1;
int i = 0;
boolean finished = false;
long loopCount = 0;
System.out.println("Start");
long startTime = System.nanoTime();
while (!finished) {
loopCount++;
intArray[i]++;
if (intArray[i] >= FINISH_TRIGGER) finished = true;
else if (i <(ARRAY_LENGTH - 1)) i++;
else i = 0;
}
System.out.println("Finish: " + loopCount + " loops; " +
((System.nanoTime() - startTime)/1e9) + " secs");
// 5 executions in range 5.98 - 6.17 secs (each 9999999801 loops)
}
}
C 代码:
//cpp_test.cpp:
#include <iostream>
#include <sys/time.h>
int main() {
const int ARRAY_LENGTH = 100;
const int FINISH_TRIGGER = 100000000;
int *intArray = new int[ARRAY_LENGTH];
for (int i = 0; i < ARRAY_LENGTH; i++) intArray[i] = 1;
int i = 0;
bool finished = false;
long long loopCount = 0;
std::cout << "Startn";
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long long startTime = (1000000000*ts.tv_sec) + ts.tv_nsec;
while (!finished) {
loopCount++;
intArray[i]++;
if (intArray[i] >= FINISH_TRIGGER) finished = true;
else if (i < (ARRAY_LENGTH - 1)) i++;
else i = 0;
}
clock_gettime(CLOCK_REALTIME, &ts);
double elapsedTime =
((1000000000*ts.tv_sec) + ts.tv_nsec - startTime)/1e9;
std::cout << "Finish: " << loopCount << " loops; ";
std::cout << elapsedTime << " secsn";
// 5 executions in range 33.07 - 33.45 secs (each 9999999801 loops)
}
我唯一可以让C 程序以优于Java的时间是使用分析信息。这表明运行时信息(默认情况下是Java获取(允许更快执行。
除了非平凡的if语句外,您的程序中没有什么发生的。也就是说,在没有分析整个程序的情况下,很难预测最有可能的分支。这使我相信这是一个分支机构错误预测的问题。现代CPU进行管道说明,允许更高的CPU吞吐量。但是,这需要预测下一个执行指令是什么。如果猜测是错误的,则必须清除指令管道,并加载正确的说明(这需要时间(。
在编译时,编译器没有足够的信息来预测最可能的分支。CPU也做了一些分支预测,但这通常沿着循环的线路和IF(而不是(。
。 但是,java具有能够在运行时使用信息以及编译时间的优势。这使Java可以将中间分支识别为最频繁的分支,因此可以预测该分支。
gcc和clang均无法展开此循环,甚至在-O3和-OS中拔出不变性,但是Java却可以。
java的最终夹具组装代码与此相似(实际上重复两次(:
while (true) {
loopCount++;
if (++intArray[i++] >= FINISH_TRIGGER) break;
loopCount++;
if (++intArray[i++] >= FINISH_TRIGGER) break;
loopCount++;
if (++intArray[i++] >= FINISH_TRIGGER) break;
loopCount++;
if (++intArray[i++] >= FINISH_TRIGGER) { if (i >= ARRAY_LENGTH) i = 0; break; }
if (i >= ARRAY_LENGTH) i = 0;
}
使用此循环,我得到了C 和Java之间完全相同的时间(6.4s(。
为什么这是合法的?因为ARRAY_LENGTH
为100,这是4个倍数。因此,i
只能超过100,并将每4个迭代重置为0。
这似乎是GCC和Clang改进的机会;他们无法展开迭代总数未知的循环,但是即使强迫展开,他们也无法识别仅适用于某些迭代的循环的一部分。
关于您在更复杂的代码中的发现(又称现实生活(:Java的优化器对小循环非常有用,其中已经进行了很多思考,但是Java在虚拟呼叫和GC上浪费了很多时间。<<<<<<<<<<<<<<<<<<<<
最后,它归结为在混凝土架构上运行的机器说明,无论谁提出了最好的套装,胜利。不要以为编译器将"做正确的事情",外观和生成的代码,配置文件,重复。
例如,如果您将循环重组一点:
while (!finished) {
for (i=0; i<ARRAY_LENGTH; ++i) {
loopCount++;
if (++intArray[i] >= FINISH_TRIGGER) {
finished=true;
break;
}
}
}
然后,C 将胜过Java(5.9s vs 6.4s(。(修订的C 组件(
,如果您可以轻微的超支(到达出口条件后增加更多的intArray
元素(:
while (!finished) {
for (int i=0; i<ARRAY_LENGTH; ++i) {
++intArray[i];
}
loopCount+=ARRAY_LENGTH;
for (int i=0; i<ARRAY_LENGTH; ++i) {
if (intArray[i] >= FINISH_TRIGGER) {
loopCount-=ARRAY_LENGTH-i-1;
finished=true;
break;
}
}
}
现在,Clang能够向量化循环并达到 3.5S vs. Java的 4.8S 的速度(不幸的是,GCC仍然无法向量化(。/p>
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 为什么 printf 在 C++ 中的执行速度比 cout 快?另外scanf比cin慢,为什么?
- C++ OpenMP 斐波那契:1 个线程的执行速度比 4 个线程快得多
- JIT 编译器及其在 C++ 前面加快 .NET 中程序执行速度的好处
- 与Java相比,为什么此C 代码执行速度如此慢
- 通过创建单个线程来运行一段代码可加快执行速度
- 如何在C 中修复执行速度不一致
- 如何在不冻结线程/应用程序的情况下减慢方法执行速度
- 优化一个简单的方程式,用于C 中的执行速度
- 由于包含标头,代码执行速度减慢
- 简单的Thrust代码的执行速度大约是我的cuda内核的一半.我用Thrust错了吗
- std::map in class:在执行速度和内存使用之间进行权衡
- 函数大小与执行速度
- 如何测量Arduino函数的执行速度?
- 以下哪项执行速度更快
- 写入数组时,最后一个线程的执行速度比第一个线程慢
- 比较执行速度
- DLL对执行速度的影响
- 如何使用内联函数加快c++的执行速度
- 简单的加法示例:共享内存版本的reduce执行速度比全局内存慢