冒泡排序基准测试中Java为何快于开启O2/O3优化的C++
冒泡排序基准测试:C++性能反低于Java的疑问
听同事提及C运行速度快于Java,在追求极致性能的场景(尤其是金融类应用)中通常优先选择C,但在简单冒泡排序基准测试中观测到了相反结果,希望大家指出本次实验的设计缺陷,或补充相关科学分析维度。
前置说明
- 编译C++代码时已使用
-O3(最高级别优化)、-O2编译选项 - 文中附带两种语言完整、简短的可运行源代码,可自行在本地机器运行、修改、验证结论
- 两份源代码并排对比可确认,二者实现逻辑完全等价
- 补充测试记录:已尝试使用
clang++和g++搭配多种优化选项(-O2、-O3、-Os、-march=native等)编译C代码,所有测试结果均慢于Java。目前判断若要让C性能反超,需要分析生成的汇编代码并开展汇编编程优化,同时想了解在大型真实应用开发中,汇编编程与汇编调试方案的实用性。
基准测试执行流程
- 在堆(而非栈)上创建int类型数组
- 启动计时器
- 填充数组元素
- 使用冒泡排序算法对数组排序
- 停止计时器
- 上述流程共执行1000万次,丢弃前100万次预热运行结果,统计输出平均耗时、最小耗时、最大耗时。
测试结果
C++测试结果(使用-O3和-O2编译)
$ g++ --version g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 $ g++ TimeBubbleSort.cpp -o TimeBubbleSort -std=c++11 -O3 $ ./TimeBubbleSort 10000000 1000000 60 Value computed: 18300000000 Iterations: 9000000 | Avg Time: 1202 | Min Time: 1158 | Max Time: 212189 $ g++ TimeBubbleSort.cpp -o TimeBubbleSort -std=c++11 -O2 $ ./TimeBubbleSort 10000000 1000000 60 Value computed: 18300000000 Iterations: 9000000 | Avg Time: 1337 | Min Time: 1307 | Max Time: 36650
Java测试结果
$ java -version java version "17.0.1" 2021-10-19 LTS Java(TM) SE Runtime Environment (build 17.0.1+12-LTS-39) Java HotSpot(TM) 64-Bit Server VM (build 17.0.1+12-LTS-39, mixed mode, sharing) $ javac -cp . TimeBubbleSort.java $ java -cp . TimeBubbleSort 10000000 1000000 60 Value computed: 18300000000 Iterations: 9000000 | Avg Time: 837.0 | Min Time: 812 | Max Time: 37196
完整可运行代码
C++代码
#include <iostream> #include <limits> #include <sstream> using namespace std; // 编译命令: g++ TimeBubbleSort.cpp -o TimeBubbleSort -std=c++11 -O3 // 执行命令: ./TimeBubbleSort 10000000 1000000 60 long get_nano_ts(timespec* ts) { clock_gettime(CLOCK_MONOTONIC, ts); return ts->tv_sec * 1000000000 + ts->tv_nsec; } struct mi { long value; }; void swapping(int &a, int &b) { int temp; temp = a; a = b; b = temp; } void bubbleSort(int *array, int size) { for(int i = 0; i < size; i++) { bool swaps = false; for(int j = 0; j < size - i - 1; j++) { if(array[j] > array[j+1]) { swapping(array[j], array[j+1]); swaps = true; } } if (!swaps) break; } } void doSomething(int *array, int size) { for(int z = 0; z < size; z++) { array[z] = size - z; } bubbleSort(array, size); } int main(int argc, char* argv[]) { int iterations = stoi(argv[1]); int warmup = stoi(argv[2]); int arraySize = stoi(argv[3]); struct timespec ts; long long x = 0; long long totalTime = 0; int minTime = numeric_limits<int>::max(); int maxTime = numeric_limits<int>::min(); int * array = (int*) malloc(arraySize * sizeof(int)); for(int i = 0; i < iterations; i++) { long start = get_nano_ts(&ts); doSomething(array, arraySize); long end = get_nano_ts(&ts); for(int j = 0; j < arraySize; j++) { x += array[j]; } int res = end - start; if (res <= 0) res = 1; if (i >= warmup) { totalTime += res; minTime = min(minTime, res); maxTime = max(maxTime, res); } } int count = iterations - warmup; double avg = totalTime / count; cout << "Value computed: " << x << endl; stringstream ss; ss << "Iterations: " << count << " | Avg Time: " << avg; if (count > 0) { ss << " | Min Time: " << minTime << " | Max Time: " << maxTime; } cout << ss.str() << endl << endl; free(array); return 0; }
Java代码
public class TimeBubbleSort { // 编译命令: javac -cp . TimeBubbleSort.java // 执行命令: java -cp . TimeBubbleSort 10000000 1000000 60 private static void swapping(int[] array, int x, int y) { int temp = array[x]; array[x] = array[y]; array[y] = temp; } private static void bubbleSort(int[] array, int size) { for(int i = 0; i < size; i++) { int swaps = 0; // 标记本轮是否发生交换 for(int j = 0; j < size - i - 1; j++) { if (array[j] > array[j + 1]) { // 当前元素大于后续元素时交换 swapping(array, j, j + 1); swaps = 1; } } if (swaps == 0) break; // 本轮无交换,数组已有序,提前退出 } } private final static void doSomething(int[] array, int size) { for(int z = 0; z < size; z++) { array[z] = size - z; } bubbleSort(array, size); } public static void main(String[] args) { int iterations = Integer.parseInt(args[0]); int warmup = Integer.parseInt(args[1]); int arraySize = Integer.parseInt(args[2]); long x = 0; long totalTime = 0; long minTime = Long.MAX_VALUE; long maxTime = Long.MIN_VALUE; int[] array = new int[arraySize]; for(int i = 0; i < iterations; i++) { long start = System.nanoTime(); doSomething(array, arraySize); long end = System.nanoTime(); for(int j = 0; j < arraySize; j++) { x += array[j]; } int res = (int) (end - start); if (res <= 0) res = 1; if (i >= warmup) { totalTime += res; minTime = Math.min(minTime, res); maxTime = Math.max(maxTime, res); } } int count = iterations - warmup; double avg = totalTime / count; StringBuilder sb = new StringBuilder(); sb.append("Value computed: ").append(x).append("\n"); sb.append("Iterations: ").append(count).append(" | Avg Time: ").append(avg); if (count > 0) { sb.append(" | Min Time: ").append(minTime).append(" | Max Time: ").append(maxTime); } System.out.println(sb.toString() + "\n"); } }
内容的提问来源于stack exchange,提问作者SpeedChaser
相关产品推荐
相关产品推荐

