qu napisał(a)
A ty nadęty deusiku lepiej się nie odzywaj skoro
nie masz nic do powiedzenia, rób to od czego tu jesteś - sprzątaj.
Ależ proszę Cię bardzo, obiecałem się nie mieszać ale skoro prosisz...
qu napisał(a)
fr3 napisał(a)
Pierwsza wersja jest o wiele szybsza - brak odwołań do pamięci, większa równoległość... (fdecstp i fincstp zajmują 0 cykli - są wykonywane w dekoderze instrukcji (fpu nie jest już naprawdę maszyną stosową!))
Sprawdź czy jest szybsze, bo raczej na to nie wygląda.
Po pierwsze taki znawca jak Ty powinien przedstawić konkrety. Po drugie powinien zauważyć błędy w obu kodach przedstawionych przez fr3m3na...
qu napisał(a)
for(float x = 1; x < 10; x++) suma = suma + x;
A teraz proszę Cię bardzo, popatrz w kod fr3m3na... co widzisz? U niego pętle są przerywane gdy x > 10. Druga sprawa, pierwszy kod w ogóle nie działa:
fr3 napisał(a)
fld [costam] ;zaladuj 10.0
fld1 ;zaladuj 1
fld1
fldz
;st0-suma st1-x, st2-1.0 st3=10.0
@@:
fcomi st0,st3 ;porownaj x z 10.0
fdecstp
fadd st0,st1
ja @f
fincstp
fadd st0,st1
jmp @b
@@:
fincstp
Aby chociaż warunek był poprawny wartość costam musi zostać zmniejszona o 1. Skoro x jest w st1 to dlaczego x jest porównywany z wartością graniczną? Stos powinien zostać zinkrementowany podczas wchodzenia w pętlę aby licznik był w st0, teraz zaś wartość graniczna jest w st2, nie st3. Moment skoku jest źle dobrany, zaś fincstp na wyjściu z pętli usunie sumę z st0. A właśnie, co z tymi trzema dodatkowymi wartościami na stosie koprocka?
Jeżeli o drugi kod chodzi to jedynie warunek zakończenia jest błędny. Na szybko do testów wydajności skleciłem takie coś. Wszystkie skoki w pętlach wyrównane do 16, dane do 4, kody poprawiłem:
format PE Console
ITER = 10000000
section '.baiji' code readable executable
finit
call get_time
mov ecx, ITER
align 0x10
_kod1:
fld [costam]
fld1
fsub st1, st0
fld1
fldz
fincstp
@@:
fcomi st0, st2
fdecstp
ja @f
fadd st0, st1
fincstp
fadd st0, st1
jmp @b
align 0x10
@@:
fstp [suma]
ffreep st0
ffreep st0
ffreep st0
dec ecx
jnz _kod1
call get_time
mov ecx, ITER
align 0x10
_kod2:
push 1
fldz
mov ebx, esp
db 0x8d, 0x80, 0, 0, 0, 0 ; lea eax, [eax+0] ; imm32 - odpowiednik nop'a
db 0x8d, 0x49, 0 ; lea ecx, [ecx+0] - imm8
nop ; lacznie wyrownanie do 16.
@@:
cmp dword [ebx], 10
jge @f
fild dword [ebx]
faddp st1, st0
inc dword [ebx]
jmp @b
align 0x10
@@:
pop edx
dec ecx
jnz _kod2
call get_time
call print_time
call print_time
pop ecx ecx
retn
get_time:
xor eax, eax
cpuid
rdtsc
pop ecx
push eax
push edx
push ecx
retn
print_time:
pop ecx
pop edx
pop eax
push ecx
sub eax, [esp]
sbb edx, [esp+4]
push eax
push edx
push _format
call [printf]
add esp, 0x0c
retn
section '.data' data readable writeable
_format db 'cykli: %08lx%08lx', 0x0d, 0x0a, 0
align 0x10
costam dd 10.0
suma dd 0.0
align 0x20
data import
dd 0, 0, 0, rva msvcrt, rva printf
rd 5
end data
msvcrt db 'msvcrt.dll', 0
printf dd rva @f, 0
@@: db 0, 0, 'printf', 0
Kompilacja fasmem, kod jest całkowicie niezależny od zewnętrznych nagłówków itd... Wyniki oczywiście nie będą dokładne, pomiary dokonywane podczas normalnej pracy systemu, ale wystarczą. Ten printf jest dosyć wredny ale nie chciało mi się konwertera pisać, niestety printf z msvcrt nie obsługuje long long, trzeba było zrobić to j\w. Wyniki:
bash-2.03$ ./times.EXE
cykli: 00000006448fbe60
cykli: 000000009292c261
bash-2.03$ ./times.EXE
cykli: 00000004c8626214
cykli: 0000000087955e30
bash-2.03$ ./times.EXE
cykli: 00000006a9fd7980
cykli: 000000007cf1cef6
C:\times.EXE
cykli: 0000000545108da4
cykli: 00000000b3f5e755
C:\times.EXE
cykli: 00000004dbc0dc12
cykli: 000000004015d04b
C:\.times.EXE
cykli: 000000057ee6d748
cykli: 00000000df21cf69
C:\>times.EXE
cykli: 0000000527282c3a
cykli: 0000000102ce61f5
C:\>times.EXE
cykli: 000000053f83a052
cykli: 000000011c39381d
C:\>times.EXE
cykli: 00000005f7a73f22
cykli: 00000000d0197b35
fr3 napisał(a)
Pierwsza wersja jest o wiele szybsza - brak odwołań do pamięci, większa równoległość... (fdecstp i fincstp zajmują 0 cykli - są wykonywane w dekoderze instrukcji (fpu nie jest już naprawdę maszyną stosową!))
Cóż, wyniki mówią same za siebie, nie muszą być dokładne. Fantazyjny kod fr3m3na jest po prostu wolny... fr3, sam pisałeś jak szybki jest dostęp do danych w cache'u - w nim mieszczą się wartości tymczasowe drugiego algorytmu, obroty stosu fpu zaś jednak kosztują, chociażby czas dekoderów. Dobra, czyli teoretyzowanie nt. szybkości algorytmów mamy z głowy? Hm... nie całkiem:
einstein^2 napisał(a)
Wybaczcie Panowie, ale zamiast schodzić do asma czy bawić się w inny sposób, czy nie sądzicie, że ten konkretny kod można zoptymalizować dużo prościej:
float suma=45;
Tu by wypadało zaznaczyć, że kompilatory z GCC, ICC czy Microsoftu od jakiegoś czasu zwykle radzą sobie z obliczaniem stałych wyrażeń podczas kompilacji, zabawki Borlanda już nie zawsze... Tak jest toretycznie, w praktyce nie wygląda to tak różowo, ICC chwilowo pod ręką nie mam. Dowody:
float licz (void)
{
float suma=0;
int x;
for(x = 1; x < 10; x++) suma = suma + x;
return suma;
}
int main ()
{
return (int) licz();
}
GCC 4.2 z -O3:
.text:00000000 public _licz
.text:00000000 _licz proc near
.text:00000000 push ebp
.text:00000001 mov ebp, esp
.text:00000003 fld ds:flt_34
.text:00000009 leave
.text:0000000A retn
.text:0000000A _licz endp
;...
.rdata:00000034 flt_34 dd 4.5e1
Z main był wywoływany licz i procka konwertująca na int. Standardowe ustawienia VC 2k5:
.text:00401000 licz proc near ; CODE XREF: _mainp
.text:00401000
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 push ecx
.text:00401001 fld1
.text:00401003 fadd ds:__real@0000000000000000
.text:00401009 fstp [esp+4+var_4]
.text:0040100C fld [esp+4+var_4]
.text:0040100F fadd ds:__real@4000000000000000
.text:00401015 fstp [esp+4+var_4]
.text:00401018 fld [esp+4+var_4]
.text:0040101B fadd ds:__real@4008000000000000
.text:00401021 fstp [esp+4+var_4]
.text:00401024 fld [esp+4+var_4]
.text:00401027 fadd ds:__real@4010000000000000
.text:0040102D fstp [esp+4+var_4]
.text:00401030 fld [esp+4+var_4]
.text:00401033 fadd ds:__real@4014000000000000
.text:00401039 fstp [esp+4+var_4]
.text:0040103C fld [esp+4+var_4]
.text:0040103F fadd ds:__real@4018000000000000
.text:00401045 fstp [esp+4+var_4]
.text:00401048 fld [esp+4+var_4]
.text:0040104B fadd ds:__real@401c000000000000
.text:00401051 fstp [esp+4+var_4]
.text:00401054 fld [esp+4+var_4]
.text:00401057 fadd ds:__real@4020000000000000
.text:0040105D fstp [esp+4+var_4]
.text:00401060 fld [esp+4+var_4]
.text:00401063 fadd ds:__real@4022000000000000
.text:00401069 fstp [esp+4+var_4]
.text:0040106C fld [esp+4+var_4]
.text:0040106F pop ecx
.text:00401070 retn
.text:00401070 licz endp
gdzie kolejne :__real@... to kolejne stałe - 1.0, 2.0, 3.0...
Natomiast przy ustawieniu na jak najmniejszy kod funkcja licz została włączona w main:
.text:00401003 push ecx
.text:00401004 push ecx
.text:00401005 fldz
.text:00401007 mov [ebp+var_4], 1
.text:0040100E fstp [ebp+var_8]
.text:00401011
.text:00401011 loc_401011: ; CODE XREF: _main+21j
.text:00401011 fild [ebp+var_4]
.text:00401014 inc [ebp+var_4]
.text:00401017 cmp [ebp+var_4], 0Ah
.text:0040101B fadd [ebp+var_8]
.text:0040101E fstp [ebp+var_8]
.text:00401021 jl short loc_401011
.text:00401023 fld [ebp+var_8]
Sytuacja się chyba nieco wyjaśniła?
Teraz może powiem na sucho kilka słów o użyciu liczb zmiennoprzecinkowych. W przypadku C czy C++ sprawa jest jasna, jeżeli część wyrażenia jest liczbą zmiennoprzecinkową wynik takiego wyrażenia również nią jest... Nie ma znaczenia do czego przypisujesz, konwersja jest dokonywana w momencie przypisania, po wykonaniu całej prawej strony. Przypisujesz to do inta? Całe wyrażenie jest ewaluowane jako float /ew. wyodrębiniane są niezależne operacje na liczbach całkowitych i liczone oddzielnie/ i konwertowane. Z resztą popatrzcie na powyższe kody, użyte kompilatory są zgodne ze standardami. Fr3 ma rację, sposób konwersji można zmienić. Odsyłam do dokumentacji kompilatorów itd...
Nie obchodzi mnie wasz durny spór, może byście się zainteresowali jak to jest zrealizowane, jakie są założenia...
Nadęty deusik? Cóż, napisałem co było do napisania, konkretnie i rzeczowo na oryginalny temat tego wątku. Jakieś UFO zarzuciło mi niewiedzę, zaczęło bluzgać, gdy trzeba było konkrety podać to dziwnym trafem zniknęło... pewnie Marooned z Lofiksem odwiedzili chłopaka... Zawsze gdy ktoś napisze coś konkretnego zjawiają się od razu specjaliści gotowi krytykować bez podawania konkretów. Stwierdziłem, że mieszać się nie będę, zdawkowo komentowałem jedynie wyczyny niektórych.
Ludzie, poczytajcie dokumentację, sprawdźcie swoje teorie zanim coś napiszecie... przestaje mnie to bawić. Dlaczego rozważam wyczyszczenie tego tematu? Tylko pierwsza strona coś wnosi, kolejne to przede wszystkim różne herezje przeplatane niedomówieniami i sporami. PHP szybsze od kodu maszynowego... muszę link do tamtego postu do perełek dodać...
Jeszcze jedna sprawa, owszem popełniłem błąd, tak jak fr3 powiedział, 'tylko' na P4, nie zaś jak stwierdziłem - 'od'.
Hm... czas jaki miałem poświęcić na doskonalenie się w lispie poświęciłem na napisanie tego postu :/
OK, mam nadzieję, że przywróciłem nieco porządku w temacie?