Prędkość Javy

1

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

0

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.

0

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.

1

Pokaż benchmark, a powiem Ci co zepsułeś.
Pewnie trafiłeś na Dead Code Elimination.

0

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.

0
  1. Trzeba by porównać dokładnie wyniki. Może masz jakiś błąd.
  2. 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.
  3. 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();
  1. Próbowałem skompilowac C++ na g++ ale jakaś masakra w ilości błędów. -std=c++11 nie pomogło
  2. @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.

2

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

0

A jakie są czasy z pustym solve() ? Czy przypadkiem te generatory nie zjadają większości czasu, a nie samo rozwiązanie :-)

0

https://bulldogjob.pl/news/232-ktory-jezyk-programowania-jest-najszybszy - są przypadki, gdzie Java jest szybsza niż C++.

0

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.

0

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,

0

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).

0

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
0

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/

0

Kolejny głupi wątek typu Php vs C++, Fortran vs Rust albo "czy opłaca się pisać gry na pc w php?".

1 użytkowników online, w tym zalogowanych: 0, gości: 1