Co będzie wydajniejsze na x86?

Co będzie wydajniejsze na x86?
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

Mam dwa kody (architektura x86):

Kopiuj
fld tword [pewna stała]
fstp tword [inna stała]

oraz

Kopiuj
mov eax, dword [pewna stała+0]
mov ebx, dword [pewna stała+4]
mov cx, word [pewna stała+8]
mov dword [inna stała+0], eax
mov dword [inna stała+4], ebx
mov word [inna stała+8], cx

Pytanie brzmi - który z nich jest wydajniejszy?
Ogólnie ich celem jest skopiowanie 80-bitowego floata z jednego miejsca w pamięci do drugiego; niby mógłbym wykonać jakiś benchmark, lecz odnoszę wrażenie, że na takim krótkim kodzie miałbym problemy z mierzeniem czasu (:P), stąd wolę zapytać znawców ;)


edytowany 3x, ostatnio: Patryk27
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:2 minuty
0

Nie wiem co będzie szybsze, ale jak już robić benchmarki to porównać też z tym:

Kopiuj
mov esi, pewna stała
mov edi, inna stała
cld
movsd
movsd
movsw
lukasz1235
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad 8 lat
  • Postów:1105
2

GCC generuje wersję drugą, pewnie nie bez powodu.
Dodatkowo dokumentacja Intela wspomina, że instrukcje x87 mają dodatkowy narzut czasowy.
Jeśli możesz skorzystać SSE to proponowałbym wyrównać zmienne do 16 bajtów i użyć movdqa.
Ale dlaczego chcesz w ogóle to optymalizować? Przy takiej ilości danych zauważalnej różnicy nie będzie. Chyba, że chcesz przenosić wiele takich long double'i to napisz, bo to trochę zmienia postać rzeczy.

EDIT:
OK, zrobiłem benchmarki. Oto wyniki:

Kopiuj
[bits 32]
[section .text]
[global main]
main:
mov ecx, 0xffffffff
l1:
   fld tword [src]
   fstp tword [dst]
   loop l1
xor eax, eax
ret
 
[section .data]
src: dt 128.256
dst: dt 0.0
Kopiuj
real        0m11.470s
user        0m11.408s
sys        0m0.000s
Kopiuj
[bits 32]
[section .text]
[global main]
 
main:
mov ecx, 0xffffffff
l1:
   mov eax, dword [src+0]
   mov ebx, dword [src+4]
   mov dx, word [src+8]
   mov dword [dst+0], eax
   mov dword [dst+4], ebx
   mov word [dst+8], dx
   loop l1
xor eax, eax
ret
 
[section .data]
src: dt 128.256
dst: dt 0.0
Kopiuj
real        0m7.718s
user        0m7.720s
sys        0m0.000s
Kopiuj
[bits 32]
[section .text]
[global main]
 
main:
mov ecx, 0xffffffff
l1:
   mov esi, src
   mov edi, dst
   cld
   movsd
   movsd
   movsw
   loop l1
xor eax, eax
ret
 
[section .data]
src: dt 128.256
dst: dt 0.0
Kopiuj
real        0m26.316s
user        0m26.328s
sys        0m0.000s

To mnie nieźle zaskoczyło.

Kopiuj
[bits 32]
[section .text]
[global main]
 
main:
mov ecx, 0xffffffff
l1:
   movdqa xmm0, [src]
   movdqa [dst], xmm0
   loop l1
xor eax, eax
ret
 
[section .data]
align 16
src: dt 128.256
align 16
dst: dt 0.0
align 16
Kopiuj
real        0m6.388s
user        0m6.344s
sys        0m0.000s

Czyli wersja z SSE jest faktycznie najszybsza (przynajmniej na moim komputerze).

edytowany 7x, ostatnio: lukasz1235
msm
Nie powinno Cię zaskoczyć, movs* są od dawna niezalecane i dodatkowo to jedyny kod którego procesor nie może zrównoleglić.
lukasz1235
Tzn. nie zaskoczyło mnie to, że kod jest wolniejszy tylko to, że różnica jest taka ogromna. Faktycznie zrównoleglenie daje dużego kopa wydajności.
Wibowit
Za to rep* movs* mogą działać w miarę szybko.
Azarien
spodziewałem się że movs będzie wolniejsze, ale żeby aż tak?
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
1
lukasz1235 napisał(a)

Ale dlaczego chcesz w ogóle to optymalizować?

Piszę kompilator JIT i zastanawiałem się, które z tych dwóch rozwiązań będzie wydajniejsze.

Czyli wersja z SSE jest faktycznie najszybsza (przynajmniej na moim komputerze).

Niestety te moje adresy nie są wyrównane do 16 bajtów (oraz miałbym spory problem próbując je zaalokować na takich adresach), więc użycie tego odpada :P

Wniosek: wersja ze zwykłymi mov wypada lepiej, niż zaciąganie do tego FPU - pora więc zmienić parę rzeczy w kompilatorze ;)


edytowany 2x, ostatnio: Patryk27
lukasz1235
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad 8 lat
  • Postów:1105
3
Patryk27 napisał(a):

Niestety te moje adresy nie są wyrównane do 16 bajtów (oraz miałbym spory problem próbując je zaalokować na takich adresach), więc użycie tego odpada :P
Skoro piszesz kompilator to zaimplementowanie wyrównania jest bardzo ważne dla wydajności:
Assembler/Compiler Coding Rule 46. (H impact, H generality) Align data on natural operand size address boundaries. If the data will be accessed with vector instruction loads and stores, align the data on 16-byte boundaries.
Ogólnie polecam przeczytać "Intel® 64 and IA-32 Architectures Optimization Reference Manual".

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

Kiedyś czytałem o tym, że wyrównanie adresów zwiększa wydajność, lecz wypadło mi z głowy - dzięki, pora nieco odświeżyć pamięć :D


Bartosz Wójcik
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 4 lata
  • Postów:439
0
Azarien
czytam ten blog od jakiegoś czasu. zacząłem od początku, jestem na 2005 ;)
Bartosz Wójcik
Chen co kilka dni dodaje posty, ale jak to się czyta to można dojść do wniosku, że w WinAPI jest cholernie dużo pułapek i małych detalików, o których nie można dowiedzieć się z dokumentacji, no ale dla Chena to są "oczywiste" sprawy :)
Azarien
wyciągnąłem trochę inny wniosek: większość tych pułapek i detalików wynika wprost lub pośrednio z dokumentacji, ale nie dowiesz się o nich kopiując niezrozumiałe skrawki kodu z tutoriali.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)