Jste si jisty ze dela jen polovinu podminek? Ja si to myslel na prvni pohled taky, ale nevypada to tak. Ja teda v cecku nic nenapsal uz hezkych par let, ale mam pocit, ze ten odkomentovany radek v cyklu by musel vypadat jinak, aby to "skakalo po dvou". Cekal bych tam neco jako (*y)++ a ne jen y++, protoze takhle to jen hybe s tim ukazatelem.
No, smiruji se s tim, ze je to na me moc slozite. :-)
Mas pravdu! Ted jsem si to ale vyzkousel a odkementovana verze bezi o tri procenta dele. Takze otazku "Proc bezi rychleji?" pokladam za nesmyslnou. Uz s optimalizaci -O1 prekladac pozna prazdny cyklus a vysledek je v obou pripadech 0.
Pokud se v odkomentovane verzi zmeni 7. radek na int &y = i; a program se prelozi jako C++, dojde k zrychleni, ktere jsem popisoval, a to asi o 9 %.
Testovano na i686 AMD Athlon(tm) XP 1800+ AuthenticAMD GNU/Linux s gcc 4.1.2. Sypu si popel na hlavu.
Opravdu? Vždyť y++ prostě posunuje hodnotu ukazatele a samotná hodnota i se vůbec nemění. Schválně si tam přidej čítač a porovnej oba výstupy. Aby platilo to, co říkáš, muselo by být na onom řádku (*y)++.
Popravde me prekvapuje, ze oba kody nebezi stejnou a to nulovou dobu. Mam tu gcc 3.4.4 a kupodivu neprijde na to, ze se tam vlastne nic nedeje.
Nicmene po odkomentovani mi kod rozhodne bezi pomaleji. Zatimco (s optimalizacemi) prvni jen dekrementuje v registru i, dokud nedojde na nulu, tak druhy jde skutecne 0-10000 a navic si jeste promennou nesmyslne uklada do pameti (asi vznikle zmatkem pri alokaci registru pro y, ktere se pak vyhodi). y spravne ignoruji oba kody.
Hmmm. Taky me to zaujalo. Vyzkousel jsem to tu prelozit na stroji na 64bitech pomoci gcc verze 4.1.2 20061115 prerelease (netlucte me, ja ten stroj nespravuju).
Pri zapnute optimalizaci (staci -O nebo -O1) to celou smycku vyhodi a program vypise 0.
Pokud ale pustim gcc bez jakehokoliv optimalizacniho prepinace, pak tu opravdu verze bez komentaru bezi rychleji: s komentarem okolo 3330000, bez komentare 2920000.
Koukal jsem trochu, co z toho gcc vyplodilo a podle mych chabych znalosti assembleru se mi jevi, ze ta verze s komentari v te smychce dela addl primo na misto v pameti, kdezto ta verze bez komentaru inkrementuje obe ty promenne v registrech.
Zajimave je to po kompilaci s Intelim prekladacem s rozbalenim smycek. Sice se jiz dneska spatne odhaduji parovani instrukci, naplneni instrukcnich pipeline atd, ale zda se me, ze Intel odvedl opravdu dobrou praci. Samozrejme je vhodne do te smycky dat neco, co prekladaci zabrani v jeji eliminaci, ale umozni jeji rozbaleni.
Tedy i[mem] = 0; i[reg] = i[mem]; while (i[reg] < 9999999) i[mem] = ++i[reg];
Se zakomentovanym to vypada zhruba:
movl $99999999, %eax
L9:
decl %eax
jns L9
gcc 4.0 oboji prelozi jako posledni kod.
%eax (ani pripadne i[mem]) uz nikde cteno neni, takze v obou pripadech je i write-only, predpokladam, ze novejsi prekladac to vyhodi uplne.
Takze vysvetleni bude asi skutecne takove, jak pise kolega vedle, v debug modu gcc nacpe kolem tolik kodu, nad kterym nepremysli, ze muze delsi kod lip nacpat pipeliny