Naiwnie napisany mandelbrot w Asm wychodzi lepiej od GCC

Odpowiedz Nowy wątek
2020-03-22 14:26

Rejestracja: 3 lata temu

Ostatnio: 1 godzina temu

Lokalizacja: U krasnoludów - pod górą

4

Ćwiczyłem sobie ostatnio System V AMD64 ABI w asmie - otak, żeby zobaczyć dlaczego jvm wypluwa taki kod jak wypluwa.
Do tego jeszcze pobieżnie spojrzałem na SSE i AVX.
Odpadem z ćwiczeń jest rysowanie mandlebrota pod xlib - gdzie algorytm zrobilem w asm.
Kod:
https://github.com/jarekratajski/yamandel

Dziwnie wyszło. Asm szybszy prawie 2 razy od gcc.
Może dlatego, że:

  • nie jestem biegły w C (20 lat nie pisze - co najwyżej oglądam i poprawiam bugi, a i to raz na ruski rok).
  • w assemblerze też podobnie - w zasadzie to znałem tylko 6502 i 68k, a w tych nie byłem biegły (a x86 był dla mnie totalnie obrzydliwy).

Jakim cudem, że moj bieda asm jest szybszy od tego co gcc produkuje ? (gcc miał tak ładnie wektoryzować) To jest tym bardziej dziwne, że ten asm powstawał na zasadzie rozpaczliwej, czasem powtarzam te same operacje bo się pogubiłem co w którym rejestrze jest - mistrzostwo świata to to na pewno nie jest :-).

Pytanie - co zepsułem?

  • coś uprościłem w asm ?
  • zrypałem parametry gcc?
  • zrypałem kod w c?

To śmieszne, np. w kontekście wątku : Jak duże spowolnienie wynika używania języków wysokiego poziomu?
Może c nie jest wysokiego poziomu, ale gcc coś powinien umieć.

Za jakiś czas sprawdze jak to robi jvm...


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 4x, ostatnio: jarekr000000, 2020-03-22 14:33

Pozostało 580 znaków

2020-03-22 14:51

Rejestracja: 4 lata temu

Ostatnio: 4 minuty temu

1

Spojrzałem na Makefile i może oprócz zestawu instrukcji dla danej architektury (-march=native), to trzeba jeszcze optymalizacja pod daną architekturę włączyć?

Using -march=native enables all instruction subsets supported by the local machine (hence the result might not run on different machines).
Using -mtune=native produces code optimized for the local machine under the constraints of the selected instruction set.

Pozostało 580 znaków

kq
2020-03-22 14:55
kq
Moderator C/C++

Rejestracja: 6 lat temu

Ostatnio: 52 minuty temu

Lokalizacja: Szczecin

2

Patrząc po makefile, kompilujesz bez optymalizacji. (CFLAGS nie jest użyte).

time of asm calculations:140450
time of c calculations:82850
time of asm calculations:218151
time of c calculations:80168
time of asm calculations:242156
time of c calculations:99624
time of asm calculations:348954
time of c calculations:92590
time of asm calculations:280319
time of c calculations:88019
time of asm calculations:252104
time of c calculations:35209

Tak mi to wygląda po dodaniu CFLAGS.

Swoją drogą, clock() to słaba funkcja do benchmarku tutaj - ona zlicza czas, ale operacje są liczone ze wszystkich wątków jednocześnie (więc w ciągu sekundy może naliczyć 16 sekund na 16 core'ach).

Swoją drogą #2, po włączeniu optymalizacji obraz się psuje, więc stawiam na błąd w kodzie: https://i.imgur.com/4jsfjbs.png


edytowany 1x, ostatnio: kq, 2020-03-22 14:56

Pozostało 580 znaków

2020-03-22 15:48

Rejestracja: 3 lata temu

Ostatnio: 1 godzina temu

Lokalizacja: U krasnoludów - pod górą

0

Normalnie liczę na jednym wątku (ustawiam zmienną, i dziwne, że CFLAGS nie jest używe bo mi się wyświetla w konsoli i widze różnice w kodzie (ustawiałem różne wersje).

W branchu https://github.com/jarekratajski/yamandel/tree/tuning
ustawiłem mierzenie czasu + dodałem oble mtune.
Nie widze róznicy.
Prosty test, jesli zwalę opcje CFLAGS na coś dziwnego pokazuje, że jednak są wykorzystywane (bo kompilacja nie działa).
Z drugiej strony miałem dziwny problem z tym, że -DCOMPARE_TO_C jakoś nie jest do C przekazwyane, więc coś może być na rzeczy.


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 1x, ostatnio: jarekr000000, 2020-03-22 15:53

Pozostało 580 znaków

kq
2020-03-22 15:49
kq
Moderator C/C++

Rejestracja: 6 lat temu

Ostatnio: 52 minuty temu

Lokalizacja: Szczecin

yamandel: yamandel.o yamandel.c yasmandel.o
    $(CC) yamandel.c -L/usr/X11R6/lib  -lpthread -lX11 yasmandel.o -o yamandel

Tutaj nie używasz, powinno być:

yamandel: yamandel.o yamandel.c yasmandel.o
    $(CC) $(CFLAGS) yamandel.c -L/usr/X11R6/lib  -lpthread -lX11 yasmandel.o -o yamandel

Nie analizowałem całości kodu, ale w tle nie latają inne wątki? Tak czy inaczej, użyłbym C++ <chrono> do mierzenia czasu, albo jakichś posixowych funkcji, a nie clock().


To było to ! - jarekr000000 2020-03-22 15:54

Pozostało 580 znaków

2020-03-22 15:55

Rejestracja: 3 lata temu

Ostatnio: 1 godzina temu

Lokalizacja: U krasnoludów - pod górą

1

To było to. Teraz jest dobrze i C jest szybsze ! Teraz poanalizuje co produkuje gcc i będęm się jarał :-)

EDIT: te artefakty (bug) się pojawiały jak jednoczesnie na wielu wątkach było liczenie i w c i w asm -> po tej samej tablicy.
Chociaż imo... nie powinny, ale pewnie czegoś nie wiem... co może być istotne. (Znalazłem - zrobiłem optymalizacje w asm - nie wyszła - czegoś się muszę douczyć).

W kodzie produkowanym przez gcc pojawiło się kilka instrukcji.....DD (czyli faktycznie na wektorach).
-mtune=native chyba nic nie zmienia (nie w czasach i nie w krytycznym kodzie).
EDIT2: po bardziej kryrycznym przeglądzie - kod jest szybszy, ale jednak użycie wektorów nadal słabe (chyba się skusze na wyprzedzenie tego w asm).


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 9x, ostatnio: jarekr000000, 2020-03-22 17:36

Pozostało 580 znaków

2020-03-22 17:03

Rejestracja: 8 lat temu

Ostatnio: 1 dzień temu

1

1) Wymiatacze robią to w C z intrinsics.
Nie jest to piękne, ale to chyba najszybsza opcja.
Tylko że to praktycznie programowanie w ASM.

Przykład #1 (niekoniecznie najszybszy): https://nullprogram.com/blog/2015/07/10/
Przykład #2: https://benchmarksgame-team.p[...]program/mandelbrot-gcc-6.html

2) Idealnie byłoby zrobić to z "omp simd", tylko wymaga to zmiany sensu pętli (trzeba robić pętlę na całym wektorze a nie na pikselu), przykład:
https://martin-ueding.de/arti[...]elbrot-performance/index.html


Szacuje się, że w Polsce brakuje 50 tys. programistów
Tak, wiem - tu chodziło troche o sprawdzenie gcc (a potem innych kompilatorów). Zgadzam się, że zamiast full asm przy ręcznym tunowaniu intrinsici były prostsze. - jarekr000000 2020-03-22 17:32
Jak juz chciałbym najszybciej to poleciałbym na gpu - akurat mandelbtrot sie do tego nieźle nadaje. - jarekr000000 2020-03-22 17:33

Pozostało 580 znaków

2020-03-22 17:21

Rejestracja: 14 lat temu

Ostatnio: 18 minut temu

2

@jarekr000000: Jeśli nadal chcesz zaklepać wersję w Javie to spróbuj z Project Panama z brancha vectorIntrinsics (trzeba sobie zbudować JDK ze źródeł): http://hg.openjdk.java.net/panama/dev/branches
W środku ma klasy reprezentujące wektory SIMD, np: http://hg.openjdk.java.net/pa[...]/classes/jdk/incubator/vector


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.

Pozostało 580 znaków

2020-03-22 19:02

Rejestracja: 16 lat temu

Ostatnio: 7 godzin temu

3
yamandel: yamandel.o yamandel.c yasmandel.o
    $(CC) $(CFLAGS) yamandel.c -L/usr/X11R6/lib  -lpthread -lX11 yasmandel.o -o yamandel

ja bym się jeszcze przyczepił że w jednej komendzie mieszana jest kompilacja C z linkowaniem, częściowo z wykorzystaniem gotowych plików .o.

Raczej w makefile kompilację robi się osobno (czy to C czy asm), a potem osobnym wywołaniem linkuje wszystko razem - przy okazji można zdefinować flagi dla linkera w LFLAGS:

CFLAGS = ...
LFLAGS = -L/usr/X11R6/lib  -lpthread -lX11

yamandel: yamandel.o yasmandel.o
    $(CC) $(LFLAGS) $^ -o [email protected]

yamandel.o: yamandel.c
    $(CC) -c $(CFLAGS) $<

yasmandel.o: yasmandel.asm
    ...

przy większej liczbie plików .c można to dalej omakrować żeby nie powtarzać reguł.

Bardzo dzięki! Z c jeszcze coś pamietam, ale w Makefile całkiem nie umiem (co zresztą było przyczyną problemu). - jarekr000000 2020-03-22 19:29

Pozostało 580 znaków

Odpowiedz

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