Dlaczego GCC? Nie lepiej MSVC?

GCC i MSVC to są dwa najpopularniejsze kompilatory* C/C++. Pierwszy, którego twórcą jest Free Software Foundation, Inc. i drugi napisany przez firmę Microsoft. Zainspirowany rozmową ze znajomym postanowiłem przeprowadzić testy optymalizacji i wydajności kodu oraz niektórych części biblioteki standardowej. Optymalizacja kodu nie jest wcale taka prosta jakby to mogło się wydawać, zwłaszcza, że konkretne przypadki trzeba z góry przewidzieć i napisać dobry algorytm – kod przecież nie jest kompilowany przez istotę inteligentną! Zdarza się wygenerować taki kod jak np.

*Niektórzy mogą się wspierać, iż gcc nie kompiluje C++. Nieprawda (flaga -lstdc++ w opcjach linkera). GCC jest skrótem od GNU Compiler Collection (najpopularniejsze polecenie to g++, choć można używać np. c++ :)). Podobnie jest z MSVC – MicroSoft Visual C++ – a polecenie – cl.

Metoda testowania i moja paczka testowa

Wszelkie kody (także assembly), wykresy, testy (pliki wejściowe), skompilowane aplikacje, skrypt (i reszta, jeżeli o czymś zapomniałem) użyte przeze mnie spakowałem do archiwum zip, aby każdy kto chce mógł przeprowadzić testy samodzielnie. Można je ściągnąć stąd (wielka waga pliku z powodu załączonych testów). W paczce opisałem jak użyć konkretnych skryptów. Skoro MSVC jest tylko pod Windowsa, więc skrypty napisałem w batchu. W celu uzyskania wiarygodnego wyniku do testowania wykorzystałem oitimetoola, który określa czas wykonania się programu na podstawie liczby instrukcji wykonanych przez procesor. Podobne narzędzia są wykorzystywane na wszelakich konkursach algorytmicznych, to konkretne jest wykorzystywane na Olimpiadzie Informatycznej.

Testowane wersje kompilatorów:
Wersja GCC: 4.7.1
Wersja MSVC: 17.00.51106.1 (VS 11)
Kompilowane poprzez skrypt (wklejam tylko linijki odpowiedzialne, za wygenerowanie .exe, cały skrypt znajduje się w paczce):

UWAGA! / Errata

Bardzo zależało mi na stworzeniu wartościowego i ciekawego artykułu i włożyłem w to mnóstwo czasu i pracy. Niestety – na marne. Jestem tylko człowiekiem i popełniłem podstawowy błąd – zapomniałem włączyć optymalizację kodu przy kompilacji za pomocą MSVC. Bardzo przepraszam za to. Poprawione wyniki znajdziecie w tabelkach pod wykresami, a poprawioną paczkę ściągniecie stąd. Z powodu braku sporej ilości czasu nie wygenerowałem nowych wykresów (TE NA STRONIE SĄ STARE = ZŁE), ani nie napisałem omówienia nowych wynikach – liczby mówią same za siebie :).
Nowe linie kompilacji:

PS i poprawiłem kod z pobieraniem adresu stringu, by nie było UB 🙂

Test 1 – pętla

Przejdźmy do pierwszego testu:

Jak widać jest to prosta pętla, która ma złożoność czasową kwadratową, a dokładniej – wykonuje się 0.5n2 + 1.5n – 1 razy (gdzie n to oczywiście c). W pierwszym teście daną wejściową jest 100000, czyli dokładnie 5’000’149’999 iteracji. Skoro najwięcej się zapamiętuje i lepiej odczytuje dane z różnego rodzaju infografik, pozwoliłem sobie wyniki zobrazować za pomocą nie najlepszej jakości wykresów (jednakże bardzo się starałem :)). Kliknij obrazek, aby powiększyć.

GCC vs MSVC - Test 1

Pętla, która wykona się ok. 5 mld razy.

Kompilator Czas wykonania pętli [s]
Test 1 – pętla (ok. 5mld iteracji)
MSVC 12.501
GCC 12.501

Wyniki – jak widać – identyczne.
Możecie się zastanawiać jaki sens ma taki prosty test. Otóż wielki! Widzicie tę różnicę na wykresie? GCC potrafi w tym przypadku dużo lepiej zoptymalizować taki króciutki kod! Pomyślcie sobie, jak będzie sprawa wyglądać przy dużo bardziej skomplikowanym kodzie.

5 myśli nt. „Dlaczego GCC? Nie lepiej MSVC?

  1. Ze skryptu kompilującego:

    cl /FA %file%.%ext% -o %file%_msvc

    %gcc% -O2 -std=c++11 %file%.%ext% -o %file%_gcc.exe

    Czyli porównywane jest GCC z -O2 oraz MSVC z /O0. Takie porównanie nie ma sensu.

  2. Ten tekst diametralnie zmieni swoją postać, gdy włączysz optymalizacje dla kompilatora MSVC. Obecnie porównujesz kod GCC optymalizowany do kodu MSVC z WYŁĄCZONĄ optymalizacją.

  3. Jeszcze jedno – porównujesz jakość kontenera std:list, a nie jakość optymalizacji kodu przez kompilatory. std::list jest beznadziejny w MSVC, więc… porównujesz dwa różne kody źródłowe i w zasadzie jest to co najwyżej ‚benchmark’ kontenera std::list oraz innych użytych narzędzi. Kiedyś sporo benchmarków robiłem różnych kontenerów i std::list pod VC++ jest na tyle beznadziejny, że należy go stosować tylko i wyłącznie tam, gdzie jest konieczność ‚wstawiania’ danych w środek iterowanej listy.

Dodaj komentarz