Zrobiłem test na Intel I3 3.6 GHz, milion układów 4-tego stopnia w C++ release, poza środowiskiem, C# i w Javie.
C++ 5.99 s
C++ tryb 64 bity 4.91 s.
C# - 5.12
Java chyba nie ma ustawień czy debug czy release, ale czas wołania dla jar - 2.64 s!
Z czego wynika ten świetny czas Javy? przydzielanie pamięci - w C++ operowałem na stosie. Obliczenia zmiennopozycyjne - wykorzystywałem tę samą bibliotekę dla Complex, ten sam algorytm liczb pseudolosowych, a obliczenia najbardziej zależą od koprocesora. Był jeden wątek.
Czyżby Java najbardziej do obliczeń numerycznych? Szkoda że w Javie nie ma przeciążania operatorów, przez co komplikuje się zapis liczb zespolonych, wektorów i macierzy.github
- Rejestracja:prawie 10 lat
- Ostatnio:ponad 5 lat
- Postów:80

- Rejestracja:prawie 9 lat
- Ostatnio:około 23 godziny
- Lokalizacja:Kraków
- Postów:402
Po pierwsze. Java może pre alokować coś co C++ prosi od systemu za każdym razem. Głównie pamięć.
Po drugie. Java posiada Just In Time compiler, który podczas działania programu na bieżąco go optymalizuje. (Sprawdza, które ify są zawsze prawdziwe i można je wywalić itp)
Po trzecie. Czy mierzysz czas obliczeń, czy również wczytywania programu? Jeżeli to drugie, czy użyłeś JDK9 i projektu modułów Jigsaw? Powinno to jeszcze bardziej skrócić czas ładowania programu.
Czy program w C++ był skompilowany z flagami optymalizacji np. -o3 ?
EDIT1: Brak przeciążania operatorów nic nie komplikuje, a tylko upraszcza. Przeciążając operatory można sobie zrobić ziaziu.


- Rejestracja:prawie 20 lat
- Ostatnio:około 2 godziny
A może masz np procesor z instrukcjami AVX i Java z nich chętnie korzysta, a reszta kompilatorów jest bardziej powściągliwa? Java zawsze próbuje JITować z użyciem wszystkich dostępnych instrukcji, bo i tak natywnego kodu po JITu nie wykorzystasz na innej maszynie.
Chociaż z drugiej strony:
Obliczenia zmiennopozycyjne - wykorzystywałem tę samą bibliotekę dla Complex, ten sam algorytm liczb pseudolosowych, a obliczenia najbardziej zależą od koprocesora.
Tę samą bibliotekę we wszystkich językach? Przecież jak miałoby to iść przez JNI to wydajność w Javie byłaby kiepska. Pokaż kod najlepiej.

- Rejestracja:ponad 8 lat
- Ostatnio:około 2 godziny
- Lokalizacja:U krasnoludów - pod górą
- Postów:4707
Pokaż benchmark, a powiem Ci co zepsułeś.
Pewnie trafiłeś na Dead Code Elimination
.
- Rejestracja:prawie 10 lat
- Ostatnio:ponad 5 lat
- Postów:80
Nie patrzyłem na optymalizację o3, mierzę czas wykonania wewnątrz programu, bez wczytywania.Ta sama biblioteka do Complex z org.apache.commons.math3 , przerobiona, nie korzysta z FastMath, ale prędkość taka sama. Przetłumaczona na C++ z C# z użyciem przeciążania operatorów, zdaje się jest dokładniejsza niż ta dostarczana z C#. Program na githubie, link dodałem w pierwszym poście.

- Rejestracja:ponad 8 lat
- Ostatnio:około 2 godziny
- Lokalizacja:U krasnoludów - pod górą
- Postów:4707
- Trzeba by porównać dokładnie wyniki. Może masz jakiś błąd.
- Jednak w Javie przypadkiem nie trafiasz na dead code elimination - czyli w sumie Java naprawde coś liczy (openjdk) i nie widzę, żeby coś sie eliminowało.
- Ale czas jaki mierzysz jest totalnie nie fair wobec javy - mierzysz czas kompilacji. Przy tak, krótkich czasach ma to wpływ.
Żeby zobaczyć jak bardzo odpal w main 2 razy
test4random();
test4random();
- Próbowałem skompilowac C++ na g++ ale jakaś masakra w ilości błędów. -std=c++11 nie pomogło
- @Wibowit używa ostro SSE
0x00007f3c111e3cbd: vmulsd %xmm5,%xmm1,%xmm0
0x00007f3c111e3cc1: vmulsd %xmm4,%xmm1,%xmm3
0x00007f3c111e3cc5: vmulsd %xmm4,%xmm2,%xmm4
0x00007f3c111e3cc9: vmulsd %xmm5,%xmm2,%xmm5
0x00007f3c111e3ccd: vsubsd %xmm0,%xmm4,%xmm4
0x00007f3c111e3cd1: vaddsd %xmm5,%xmm3,%xmm3 ;*ifne
; - util.Complex::multiply@25 (line 406)
; - polyRoots.Poly3::solve@96 (line 74)
ale pewnie po zbadaniu by wyszło, że jak zwykle niezbyt optymalnie.

- Rejestracja:ponad 13 lat
- Ostatnio:prawie 3 lata
W klasie Complex:
- nie używasz const za listą parametrów
- żaden parametr nie jest w wersji const
- żaden operator nie zwraca referencji
- nie masz wersji &&
Opcja -O3 jest niezbędna przy benchmarku, chyba że go akurat debugujesz - to nie.
http://en.cppreference.com/w/cpp/language/copy_assignment
http://en.cppreference.com/w/cpp/language/operators
W aktualnej wersji żeby to zobrazować powiedziałbym że porównujesz C++ na Raspberry Pi i Jave na Xeonie.
Edit: tutaj na końcu masz podane opcje kompilatora C++ które warto stosować przy benchmarkowaniu:
https://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexredux&lang=gpp&id=4

benchmark
to był zoptymalizowany C ze wstawkami asm, porównywany z jvm, w ktorym wiekszość czasu szła na start maszyny i początkowe wykonywanie kodu w trybie interpretacji. Tu udało się zrypać wszystkie platformy.

nowinkach
😀
- Rejestracja:około 7 lat
- Ostatnio:ponad 6 lat
https://bulldogjob.pl/news/232-ktory-jezyk-programowania-jest-najszybszy - są przypadki, gdzie Java jest szybsza niż C++.
- Rejestracja:prawie 10 lat
- Ostatnio:ponad 5 lat
- Postów:80
Wrzuciłem poprawki, aby kompilowało się z GCC wraz z projektem CodeBlocks, dodałem const za nazwami funkcji. Generatory MT zabierają mniej niż 10% całości.

- Rejestracja:prawie 8 lat
- Ostatnio:ponad 3 lata
- Lokalizacja:Warszawa
- Postów:87
Moje czasy:
C++: 1.993682 2.073570 2.037815 2.001485 2.077999 1.989976 2.072519
Java: 3.495080346 3.090479274 2.63704866 3.189946434 3.143792008 3.153356039 2.783030576
Ubuntu 16.04 na x86-64, g++ 5.4.0, Oracle JDK 8u162, .opcje g++: g++ -Wall -O3 -o bench *.cpp
, opcje javy java -server polyRoots.Main
,



- Rejestracja:ponad 8 lat
- Ostatnio:około 2 godziny
- Lokalizacja:U krasnoludów - pod górą
- Postów:4707
Ciekawe jest porównanie różnych wersji JVM: (odpalałem w pętli 10 powtórzeń i bralem ostatnie wyniki. -Xms4g -Xmx4g tak for fun).
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
czas ~= 1.28s
java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)
czas~= 1.18s
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
czas ~= 1.143s
a C++ ( niestety g++ pod cygwin).
g++ (GCC) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
g++ -O3 -fomit-frame-pointer -march=native -std=c++17 -fopenmp -flto -I . *.cpp
czas ~= 0.94s
Nadal nie mam pewności czy oba C++ i Java to samo faktycznie mierzą (precyzja, rozkład losowy itp.).
Jak sam robie taki benchmark to zrzucam sprawdzam ileś tam próbek na dysk i porównuje czy double są te dokładnie same. Inaczej to mocno może być niepewne- (btw. to jest np. ważny punkt przy testowaniu CPU vs GPU - często wychodzi, że jak się chce mieć taką dokładnie samą precyzję jak na CPU to wyniki nie są już różowe, przy pewnych symulacjach zgodność z IEEE nie ma znaczenia, ale przy pewnych ma kolosalne).

- Rejestracja:ponad 13 lat
- Ostatnio:prawie 3 lata
Projekt w Code::Blocks otworzył się bez problemu. W Eclipsie - nie bardzo.
Napisałem więc skrypty do Javy:
# build.sh
rm -rf ./target
mkdir ./target
javac -Xlint:unchecked -encoding ISO-8859-15 -d ./target ./src/**/*.java
# run.sh
java -cp ./target polyRoots.Main "$@"
Wyniki dla niezmodyfikowanych źródeł:
Java
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
Time=2.085252045
C++
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
time=1.630913
Też jestem zdania że test powinien wyświetlać końcowy wynik.
Oprócz tego budować się z konsoli.
Po zmianie operatora przypisania w C++ na:
Complex& Complex::operator=(const Complex &src)
i parametrów kompilatora na:
-march=corei7 -fomit-frame-pointer -O3
wynik dla C++ to
time=1.533322
Edit 2:
Po dodaniu rozgrzewania do Javy:
private static void test4random(boolean showTime) {
//...
if (showTime) System.out.println("Time=" + estimatedTime/1e9);
}
public static void main(String[] args) {
Locale.setDefault(new Locale("en", "US"));
int c = 10;
test4random(false);
while(c-->0)
test4random(true);
}
Time=1.675183037
Time=1.64695364
Time=1.69172101
Time=1.64810921
Time=1.644952009
Time=1.657532988
Time=1.695351254
Time=1.679284253
Time=1.679228825
Time=1.687269182
A po włączeniu w C++ dodatkowych opcji -flto -march=native
time=1.213913

- Rejestracja:prawie 20 lat
- Ostatnio:około 2 godziny
No dobra, to teraz wyniki ode mnie :) Na początek oczywiście zmieniłem wersję Javową tak, by test odpalał się 10x, a nie raz, bo nie chcemy mierzyć czasu kompilacji, a stabilny czas wykonywania.
Stan z commita: 0d51188c04084021e5c6e2557848048d1ecb5c2a
Wersja C++ daje takie wyniki (kilka razy odpalona binarka):
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
g++ -Wall -O3 -std=c++11 -o bench *.cpp
time=1.534404 sec.
time=1.529608 sec.
time=1.531132 sec.
time=1.531274 sec.
time=1.531969 sec.
Wersja Javowa daje takie wyniki (10x powtórzona główna metoda):
java version "1.8.0_161"
odpalone z IntelliJa
Time=1.99268938
Time=1.59109558
Time=1.595345558
Time=1.595759508
Time=1.595871043
Time=1.591842441
Time=1.592763768
Time=1.605932232
Time=1.574023946
Time=1.578623908
i5-4670 @ 3.8 GHz, Ubuntu 16.04 64-bit
Różnice w wydajności C++ vs Java po rozgrzaniu JVMki są jak widać kosmetyczne.
PS:
Do mierzenia wydajności krótkich metod w Javie są specjalne narzędzia jak np http://openjdk.java.net/projects/code-tools/jmh/
Aktualizacja:
Po dodaniu -flto i -march=native sytuacja się zmienia:
g++ -Wall -O3 -std=c++11 -flto -march=native -o bench *.cpp
time=1.110629 sec.
time=1.108664 sec.
time=1.110985 sec.
time=1.108843 sec.
time=1.110323 sec.
time=1.105393 sec.
Taka binarka jest jednak nieprzenośna.
PPS:
Java 9 lepiej sobie radzi z wektoryzacją niż Java 8, więc wyniki na niej powinny być lepsze. Przykład: http://prestodb.rocks/code/simd/




Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.