Linus Torvalds na YouTube kanálu Linus Tech Tips staví dokonalý linuxový počítač.
Po 9 týdnech vývoje od vydání Linuxu 6.17 oznámil Linus Torvalds vydání Linuxu 6.18. Přehled novinek a vylepšení na LWN.net: první a druhá polovina začleňovacího okna a Linux Kernel Newbies. Vypíchnout lze například podporu protokolu PSP (PSP Security Protocol, PSP encryption of TCP connections).
Byla vydána nová stabilní verze 25.11 linuxové distribuce NixOS (Wikipedie). Její kódové označení je Xantusia. Podrobný přehled novinek v poznámkách k vydání. O balíčky se v NixOS stará správce balíčků Nix.
Richard Hughes na Mastodonu oznámil, že se společnost Framework Computer stala sponzorem služby LVFS (Linux Vendor Firmware Service) umožňující aktualizovat firmware zařízení na počítačích s Linuxem.
Jak na webu co nejšíleněji zadávat datum? Jak to uživatelům co nejvíce znepříjemnit? V Bad UX World Cup 2025 (YouTube) se vybíraly ty nejšílenější UX návrhy. Vítězným návrhem se stal Perfect Date.
Společnost Collabora vydala (YouTube) na LibreOffice založený desktopový kancelářský balík Collabora Office. Pro Windows, macOS a Linux. Se stejným uživatelským rozhraním jako Collabora Online. Svůj desktopový kancelářský balík s rozhraním LibreOffice pojmenovala Collabora Office Classic.
Glen MacArthur vydal AV Linux (AVL) a MX Moksha (MXM) 25. S linuxovým jádrem Liquorix. AV Linux (Wikipedie) je linuxová distribuce optimalizována pro tvůrce audio a video obsahu. Nejnovější AV Linux vychází z MX Linuxu 25 a Debianu 13 Trixie. AV Linux přichází s desktopovým prostředím Enlightenment 0.27.1 a MX Moksha s prostředím Moksha 0.4.1 (fork Enlightenmentu).
Ubuntu pro testování nových verzí vydává měsíční snapshoty. Dnes vyšel 1. snapshot Ubuntu 26.04 LTS (Resolute Raccoon).
Zástupci členských států EU se včera shodli na návrhu, který má bojovat proti šíření materiálů na internetu zobrazujících sexuální zneužívání dětí. Nařízení známé pod zkratkou CSAM a přezdívané chat control mělo množství kritiků a dlouho nebyla pro jeho schválení dostatečná podpora. Pro schválení byla potřeba kvalifikovaná většina a dánské předsednictví v Radě EU se snažilo dosáhnout kompromisu. Návrh nakonec po dlouhých týdnech
… více »Britské herní studio Facepunch stojící za počítačovými hrami Garry's Mod a Rust uvolnilo svůj herní engine s&box (Wikipedie) jako open source. Zdrojové kódy jsou k dispozici na GitHubu pod licencí MIT. Herní engine s&box je postavený nad proprietárním herním enginem Source 2 od společnosti Valve.
Jako priklad si vezmeme faktorial:
int fact_rec(int n) {
if (n == 0) return 1;
return n * fact_rec(n - 1);
}
int fact_iter(int n) {
int r = 1;
for (int i = n; i >= 1; i--)
r *= i;
return r;
}
Pro rekurzivni faktorial generuje GCC (4.7.1) s prepinacem -O0 opravdu naivni kod.
0: push rbp 1: mov rbp,rsp 4: sub rsp,0x10 8: mov DWORD PTR [rbp-0x4],edi b: cmp DWORD PTR [rbp-0x4],0x0 f: jne 18 <fact_rec+0x18> 11: mov eax,0x1 16: jmp 29 <fact_rec+0x29> 18: mov eax,DWORD PTR [rbp-0x4] 1b: sub eax,0x1 1e: mov edi,eax 20: call 25 <fact_rec+0x25> 25: imul eax,DWORD PTR [rbp-0x4] 29: leave 2a: ret
S prepinacem -O1 uz je to o neco lepsi, jsou odstranena zbytecna prirazeni, nevytvari se zbytecne ramec na zasobniku, jenom obsah registru ebx se uklada na zasobnik, ale porad je to kod, ktery se podoba tomu vstupnimu.
0: push rbx 1: mov ebx,edi 3: mov eax,0x1 8: test edi,edi a: je 17 <fact_rec+0x17> c: lea edi,[rdi-0x1] f: call 14 <fact_rec+0x14> 14: imul eax,ebx 17: pop rbx 18: ret
S prepinacem -O2 uz dostaveme neco trochu prekvapivejsiho, rekurze (vsimnte si, ze to neni bezna koncova rekurze) je prevedena na cyklus:
0: test edi,edi 2: mov eax,0x1 7: je 1a <fact_rec+0x1a> 9: nop DWORD PTR [rax+0x0] 10: imul eax,edi 13: sub edi,0x1 16: jne 10 <fact_rec+0x10> 18: repz ret 1a: repz ret
Pro srovnani uvadim kod vygenerovany pro funkci fact_iter s prepinacem -O2:
0: test edi,edi 2: mov eax,0x1 7: jle 1a <fact_iter+0x1a> 9: nop DWORD PTR [rax+0x0] 10: imul eax,edi 13: sub edi,0x1 16: jne 10 <fact_iter+0x10> 18: repz ret 1a: repz ret
Jak kazdy snadno nahledne, oba vystupy jsou stejne. Takze jake z toho plyne moralni ponauceni? Modre nebo zelene lentilky, stejne skonci vsechny stejnou barvou...
A jako bonus uvadim vysledek pro -O3.
0: test edi,edi 2: je 12a <fact_rec+0x12a> 8: mov edx,edi a: mov esi,edi c: shr edx,0x2 f: lea ecx,[rdx*4+0x0] 16: test ecx,ecx 18: je 130 <fact_rec+0x130> 1e: cmp edi,0x6 21: jbe 130 <fact_rec+0x130> 27: lea eax,[rdi-0x1] 2a: mov DWORD PTR [rsp-0x18],edi 2e: movdqa xmm4,XMMWORD PTR [rip+XXXXX] 35: 36: mov DWORD PTR [rsp-0x14],eax 3a: lea eax,[rdi-0x2] 3d: movd xmm2,DWORD PTR [rsp-0x14] 43: mov DWORD PTR [rsp-0x10],eax 47: lea eax,[rdi-0x3] 4a: movd xmm1,DWORD PTR [rsp-0x10] 50: mov DWORD PTR [rsp-0xc],eax 54: xor eax,eax 56: movd xmm0,DWORD PTR [rsp-0xc] 5c: punpckldq xmm1,xmm0 60: movd xmm0,DWORD PTR [rsp-0x18] 66: punpckldq xmm0,xmm2 6a: punpcklqdq xmm0,xmm1 6e: movdqa xmm1,XMMWORD PTR [rip+XXXXX] 75: 76: nop WORD PTR cs:[rax+rax*1+0x0] 7d: 80: movdqa xmm3,xmm1 84: psrldq xmm1,0x4 89: add eax,0x1 8c: movdqa xmm2,xmm0 90: cmp edx,eax 92: pmuludq xmm3,xmm0 96: paddd xmm0,xmm4 9a: psrldq xmm2,0x4 9f: pmuludq xmm2,xmm1 a3: pshufd xmm1,xmm3,0x8 a8: pshufd xmm2,xmm2,0x8 ad: punpckldq xmm1,xmm2 b1: ja 80 <fact_rec+0x80> b3: movdqa xmm2,xmm1 b7: sub edi,ecx b9: cmp esi,ecx bb: psrldq xmm2,0x8 c0: movdqa xmm0,xmm2 c4: psrldq xmm2,0x4 c9: pmuludq xmm0,xmm1 cd: psrldq xmm1,0x4 d2: pshufd xmm0,xmm0,0x8 d7: pmuludq xmm1,xmm2 db: pshufd xmm1,xmm1,0x8 e0: punpckldq xmm0,xmm1 e4: movdqa xmm1,xmm0 e8: psrldq xmm1,0x4 ed: movdqa xmm2,xmm1 f1: psrldq xmm1,0x4 f6: pmuludq xmm2,xmm0 fa: psrldq xmm0,0x4 ff: pmuludq xmm1,xmm0 103: pshufd xmm0,xmm2,0x8 108: pshufd xmm1,xmm1,0x8 10d: punpckldq xmm0,xmm1 111: movd DWORD PTR [rsp-0x18],xmm0 117: mov eax,DWORD PTR [rsp-0x18] 11b: je 137 <fact_rec+0x137> 11d: nop DWORD PTR [rax] 120: imul eax,edi 123: sub edi,0x1 126: jne 120 <fact_rec+0x120> 128: repz ret 12a: mov eax,0x1 12f: ret 130: mov eax,0x1 135: jmp 120 <fact_rec+0x120> 137: ret
Tuhle davku vogonske poezie se mi opravdu nechce rozebirat, ale vypada to, ze pro male hodnoty n (<= 6) se pouzije bezny algoritmus a na zbytek vypocet pomoci vektorovych instrukci.
Tiskni
Sdílej:
o tomto som tiez pisal blog pred 3 rokmi, ked som sa k tomu dostal niekde cez reddit.Občas se vracím k tématům, o kterých jsme už v Receptáři hovořili. Není divu, každý se nemůže dívat na všechny pořady. Tak třeba paní Emilie Bezoušková...
implementovane to je v tree-tailcall.cDiky za info, presne tohle jsem chtel vedet. Cekal jsem, ze to bude sofistikovanejsi a vychazet primo z vnitrni SSA reprezentace.
ale podla standardu sa na to neda spoliehat (a to prekvapivo ani v common lispe)V CommonLispu se podle standardu neda spolehat ani na ty tail cally.
I když pro moderní procesory je nejspíš lepší nacpat několik prefixů před jeden NOP než tam dát více "jednoduchých" NOPů, například pokud dekodér dokáže zahazovat nesmyslné prefixy.
a v jiných jazycích to tolik nevadí, protože se o to postarají prostředky samotného jazyka i bez optimalizace.V některých jazycích to jde vypnout – zejména kvůli ladění (např. v F#, k němuž se vztahovala původní diskuze).
Je sice hezké, že překladač je dost chytrý na to, aby sám převáděl rekurze na cykly, ale když se objeví nějaké chybky, tak skutečnost, že neoptimalizovaný kód, který používá k ladění, se silně liší od optimalizovaného, může být za určitých okolností docela prolbematická...To ano, ovšem v GCC by mělo jít nějakým CFLAG zapnout jednu konkrétní optimalizaci, ne? Případně by mělo jít debugovat optimalizovaný kód apod...
PS: Ty oprefixované NOPy (obvlášť ten v poslední verzi vygenerované přes -O3) mně dostalyKvůli čemu tam je? Zarovnání? Jinak jednoduché NOPy se afaik nevidí už vlastně nikdy (na x86), pokud najdeš v binárce jednoduché NOPy, nejspíš se v ní někdo hrabal
Kvůli čemu tam je? Zarovnání?Jo, kvuli zarovnani. AMD64 ma instrukcni cache o velikosti 16B, takze ma rado, kdyz jsou skoky zarovnane na 16B. Teoreticky by mely jit pouzit slozitejsi NOP i pro prefetch, ale na to mi prijde rozumnejsi pouzit primo instrukce prefetchX z SSE.
AMD64 ma instrukcni cache o velikosti 16BJako velikost jednoho cacheline?
.
Ty oprefixované NOPy (obvlášť ten v poslední verzi vygenerované přes -O3) mně dostalyOn je zajímavej i ten "repz ret". Tipoval bych to na ten prefetch jak psal deda.jabko. Pro ostatní co neví (
): "rep" je prefix cyklu a "ret" je návrat, takže tipuju, že mikrokód si při "rep" myslí, že nastane cyklus a další instrukci po "ret" nenačte, což je výhoda, protože se stejně bude skákat pryč (pro ty co ví: jak moc jsem se seknul?
).
Jinak ona je x86 tak šílená, že jí jednak nestačej volný hodnoty pro nový opkód a jednak se používaj různý kombinace i pro další věci. Například instrukce pause, což je vlastně jen sekvence dříve přeložitelná jako "rep nop". V Intelu to dělali už od začátku, schválně kdo bez internetu uhodne, co dělal původně na 80(1)86 opkód 0x0f (od zavedení chráněného módu jako prefix pro nové instrukce)?
Jinak podobné legrácky, co používá kompilátor, jsou popsané taky tady.
Jakó... To mi zní dost jako černá magie. Evidentně udělaly optimalizační metody v překladačích kus cesty kupředu od dob, kdy nás o nich nesměle učili, jak jakože umí třeba občas za vhodnej okolností vytáhnout mimo cyklus invariant... :)
Což o to, pokrok jde kupředu, ale todle mi přijde už fakt jako hodně moc. To je skoro jako kdyby ten překladač věděl, že počítáte faktoriál a prostě to celé udělal jinak, lépe a radostněji. Myslím tu poslední verzi. To mi jako někdo vysvětlete, jak todle pozná. Pochopit co dělá cizí zdroják je kolikrát problém pro člověka, ne tak pro stroj... :D
To je skoro jako kdyby ten překladač věděl, že počítáte faktoriál a prostě to celé udělal jinak, lépe a radostněji.A za chvíli ti řekne, aby sis s tou vázou nedělal starosti
Ne, váženě, ten překladač neví, že počítáš faktoriál, ale ví, že něco cyklicky děláš pomocí tail callu, a tak to převede to na cyklus.
Převádět rekurzi na cyklus a naopak jsme se učili někdy v druháku na střední v Packalu, takže jsem si jist, že pro moderní překladač to není problém....
Ne, váženě, ten překladač neví, že počítáš faktoriál, ale ví, že něco cyklicky děláš pomocí tail callu,Vtip je v tom, ze v tom prikladu neni pouzity tail call, a presto to prekladac dokazal prelozit jako cyklus.
tree-tailcall.c.
V kostce: on pracuje s tail callem ve tvaru (obecně) return a + m * func(...);, kde a ani m nezávisí na výsledku toho tail volání. Předeve to na cyklus s akumulátory (zvlášť pro aditivní a multiplikativní proměnnou podle potřeby). Klasický tail call (tedy return func(...);) je pouze specielním případem, kdy a = 0, m = 1, tedy bez akumulátoru.
Chytrej trik.
let rec map mapper = function | [] -> [] | x::xs -> mapper x :: (map mapper xs)tento map sa prelozi ako cyklus:
let map mapper list =
let rec map mapper acc = function
| [] -> acc
| x::xs -> xs |> map mapper (mapper x :: acc)
list |> map mapper [] |> List.rev
tento map sa prelozi ako rekurzia, pri velkych zoznamoch hrozi stackoverflow:Záleží na sémantice a implementaci. Např. v GHC Haskellu by byla preferována první verze.
tento map sa prelozi ako cyklus:Bohužel toto řešení není příliš efektivní a ani přehledné.
let rec map1 mapper = function
| [] -> []
| x::xs -> mapper x :: (map1 mapper xs)
let map2 mapper list =
let rec map mapper acc = function
| [] -> acc
| x::xs -> map mapper (mapper x :: acc) xs
List.rev (map mapper [] list)
let map3 mapper list =
let rec map3 cnt mapper = function
| [] -> cnt []
| x::xs -> map3 (fun l -> cnt (mapper x :: l)) mapper xs
map3 id mapper list
Podľa môjho testu:List.map. Pro OCaml jsou nějaká měření v článku Optimizing List.map.
gcc (GCC) 4.7.1 z aktuálního Slackware (vím, nemám 64bit OS
). Kompilace přes "gcc -c zzzzzzzzzzzzz.c -O0" atd.
-O0
00000000 <fact_rec>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 18 sub $0x18,%esp 6: 83 7d 08 00 cmpl $0x0,0x8(%ebp) a: 75 07 jne 13 <fact_rec+0x13> c: b8 01 00 00 00 mov $0x1,%eax 11: eb 10 jmp 23 <fact_rec+0x23> 13: 8b 45 08 mov 0x8(%ebp),%eax 16: 48 dec %eax 17: 89 04 24 mov %eax,(%esp) 1a: e8 fc ff ff ff call 1b <fact_rec+0x1b> 1f: 0f af 45 08 imul 0x8(%ebp),%eax 23: c9 leave 24: c3 ret-O1
00000000 <fact_rec>: 0: 53 push %ebx 1: 83 ec 18 sub $0x18,%esp 4: 8b 5c 24 20 mov 0x20(%esp),%ebx 8: 85 db test %ebx,%ebx a: 74 10 je 1c <fact_rec+0x1c> c: 8d 43 ff lea -0x1(%ebx),%eax f: 89 04 24 mov %eax,(%esp) 12: e8 fc ff ff ff call 13 <fact_rec+0x13> 17: 0f af c3 imul %ebx,%eax 1a: eb 05 jmp 21 <fact_rec+0x21> 1c: b8 01 00 00 00 mov $0x1,%eax 21: 83 c4 18 add $0x18,%esp 24: 5b pop %ebx 25: c3 ret-O2
00000000 <fact_rec>: 0: 8b 54 24 04 mov 0x4(%esp),%edx 4: b8 01 00 00 00 mov $0x1,%eax 9: 85 d2 test %edx,%edx b: 74 0a je 17 <fact_rec+0x17> d: 8d 76 00 lea 0x0(%esi),%esi 10: 0f af c2 imul %edx,%eax 13: 4a dec %edx 14: 75 fa jne 10 <fact_rec+0x10> 16: c3 ret 17: c3 ret-O3 == -O2 -Os
00000000 <fact_rec>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 8b 55 08 mov 0x8(%ebp),%edx 6: b8 01 00 00 00 mov $0x1,%eax b: 85 d2 test %edx,%edx d: 74 06 je 15 <fact_rec+0x15> f: 0f af c2 imul %edx,%eax 12: 4a dec %edx 13: eb f6 jmp b <fact_rec+0xb> 15: 5d pop %ebp 16: c3 ret
00000000 <fact_rec>: 0: 8b 54 24 04 mov 0x4(%esp),%edx 4: b8 01 00 00 00 mov $0x1,%eax 9: 85 d2 test %edx,%edx b: 74 0d je 1a <fact_rec+0x1a> d: 8d 76 00 lea 0x0(%esi),%esi 10: 0f af c2 imul %edx,%eax 13: 83 ea 01 sub $0x1,%edx 16: 75 f8 jne 10 <fact_rec+0x10> 18: f3 c3 repz ret 1a: f3 c3 repz retKromě přidání těch repz (slackware default je i486) se změnil "dec" na "sub" (zajímavý, sub má delší opkód). Ještě zajímavější je ten "lea", což je jestli se nepletu taky jen "nop".