A jaki jest sens tworzyć kolejny microbenchmark, który testowałby właściwie tylko wektoryzację / rozwijanie pętli i proste operacje arytmetyczne? Takich microbenchmarków znajdziesz dużo na Great Language Shootout. Java nie odbiega od C++ w większości testów o więcej niż 30% (a w wielu różnica jest mniejsza).
– Dodane 26.05.2009 (Wt) 14:26 –
Wiesz, tak dla hecy zaimplementowałem ten filtr medianowy. Niech Ci będzie 
Java:
import java.util.Arrays;
public class MedianFilter {
private static int median(int[] array) {
Arrays.sort(array);
return array[array.length / 2];
}
private static void filter(int[][] input, int[][] output) {
final int HEIGHT = input.length;
final int WIDTH = input[0].length;
final int RADIUS = 2;
final int KERNEL_SIZE = (2 * RADIUS + 1);
int[] kernel = new int[KERNEL_SIZE * KERNEL_SIZE];
for (int y = RADIUS; y < HEIGHT - RADIUS; y++) {
for (int x = RADIUS; x < WIDTH - RADIUS; x++) {
int kernelIndex = 0;
for (int i = y - RADIUS; i <= y + RADIUS; i++) {
for (int j = x - RADIUS; j <= x + RADIUS; j++) {
kernel[kernelIndex++] = input[i][j];
}
}
output[y][x] = median(kernel);
}
}
}
public static void main(String[] args) {
int[][] input = new int[1000][1000];
int[][] output = new int[1000][1000];
long start = System.nanoTime();
for (int i = 0; i < 50; i++) {
filter(input, output);
}
long end = System.nanoTime();
System.out.printf("Elapsed time: %f ms\n", (end - start) / 1000000.0);
}
}
C:
#include
#include
#include
#define HEIGHT 1000
#define WIDTH 1000
#define RADIUS 2
#define KERNEL_SIZE (2 * RADIUS + 1)
int compare(const void* a, const void* b) {
return *(int*) a - *(int*) b;
}
int median(int array[], int length) {
qsort(array, length, sizeof(int), &compare);
return array[length / 2];
}
void filter(int input[][WIDTH], int output[][WIDTH]) {
int kernel[KERNEL_SIZE * KERNEL_SIZE];
int x, y, i, j, kernelIndex;
for (y = RADIUS; y < HEIGHT - RADIUS; y++) {
for (x = RADIUS; x < WIDTH - RADIUS; x++) {
kernelIndex = 0;
for (i = y - RADIUS; i <= y + RADIUS; i++) {
for (j = x - RADIUS; j <= x + RADIUS; j++) {
kernel[kernelIndex++] = input[i][j];
}
}
output[y][x] = median(kernel, KERNEL_SIZE * KERNEL_SIZE);
}
}
}
int main() {
int input[HEIGHT][WIDTH];
int output[HEIGHT][WIDTH];
struct timeval tv1;
struct timeval tv2;
int i, time;
gettimeofday(&tv1, NULL);
for (i = 0; i < 50; i++) {
filter(input, output);
}
gettimeofday(&tv2, NULL);
time = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec + 1000) % 1000;
printf("Elapsed time: %d ms\n", time);
return 0;
}
C++ (właściwie nie do końca, ale przepisałem na C++ tylko fragment odpowiedzialny za sortowanie, bo on jest wąskim gardłem algorytmu):
#include
#include
#include
#include
using namespace std;
#define HEIGHT 1000
#define WIDTH 1000
#define RADIUS 2
#define KERNEL_SIZE (2 * RADIUS + 1)
int median(int array[], int length) {
sort(array, array + length);
return array[length / 2];
}
void filter(int input[][WIDTH], int output[][WIDTH]) {
int kernel[KERNEL_SIZE * KERNEL_SIZE];
int x, y, i, j, kernelIndex;
for (y = RADIUS; y < HEIGHT - RADIUS; y++) {
for (x = RADIUS; x < WIDTH - RADIUS; x++) {
kernelIndex = 0;
for (i = y - RADIUS; i <= y + RADIUS; i++) {
for (j = x - RADIUS; j <= x + RADIUS; j++) {
kernel[kernelIndex++] = input[i][j];
}
}
output[y][x] = median(kernel, KERNEL_SIZE * KERNEL_SIZE);
}
}
}
int main() {
int input[HEIGHT][WIDTH];
int output[HEIGHT][WIDTH];
struct timeval tv1;
struct timeval tv2;
int i, time;
gettimeofday(&tv1, NULL);
for (i = 0; i < 50; i++) {
filter(input, output);
}
gettimeofday(&tv2, NULL);
time = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec + 1000) % 1000;
printf("Elapsed time: %d ms\n", time);
return 0;
}
Wyniki na moim kompie z 3 pomiarów (AMD Athlon 3700+, 1GB RAM, jeden rdzeń)
Java (java -server Median):
-
18423 ms
-
17091 ms
-
18367 ms
C (gcc median.c -O2):
- > 60 s (nie chciało mi się dłużej czekać - jedna iteracja ~1200 ms)
C++: (g++ median.cpp -O2)
-
21423 ms
-
21892 ms
-
21708 ms
C++: (g++ median.cpp -march=i686 -m3dnow -fomit-frame-pointer -O3)
-
15796 ms
-
15704 ms
-
15387 ms
I jeszcze wersje softu, którymi kompilowałem:
java version “1.6.0_12”
Java SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot Client VM (build 11.2-b01, mixed mode, sharing)
gcc (GCC) 4.2.4
Copyright © 2007 Free Software Foundation, Inc.
Wynik: Java nieznacznie wygrała z C++ ten benchmark przy typowych ustawieniach kompilatora (-O2 jest szeroko używane), za to, zgodnie z tym, czego się spodziewałem nieznacznie (<15%) przegrała przy wykosmoszonych ustawieniach kompilatora C++ (ale to jest nie fair o tyle, że 99% softu - tj. głównie bibliotek nie kompiluje się pod konkretny procesor, a pod wspólny mianownik np. 486). Benchmark wliczał czas kompilacji potrzebny na HotSpot w Javie. Być może bawiąc się opcjami gcc dałoby się wycisnąć jeszcze kilka %.
Niemniej - GDZIE JEST TWOJE KILKASET PROCENT RÓŻNICY? Proszę o przenośny i zgodny ze standardem kod w C++, który policzy to zadanie na moim kompie w mniej niż 6s (50 iteracji) - bo kilkaset % zaczyna się dla mnie od 300%.