Příručka Linux From Scratch pro sestavení základního linuxového systému byla aktualizována v pravidelném půlročním termínu. Vydání 13.1 shrnuje přes 40 nových verzí balíčků a několik patchů. Navazující příručka Beyond Linux From Scratch s recepty pro sestavení dalších knihoven a aplikací zatím vydána nebyla, ačkoliv vývojová verze stále dostává aktualizace. Lze je číst online nebo stáhnout v HTML či PDF.
Národní bezpečnostní tým CSIRT.CZ koordinovaný sdružením CZ.NIC přichází se službou Strážci internetu, která má sjednotit způsob hlášení doménových jmen zneužívaných k páchání trestné činnosti. Službu mohou uživatelé využívat také prostřednictvím rozšíření do prohlížeče. Nový nástroj podporuje jak hlášení vyžadující autorizaci, tak anonymní reporting, u kterého však nebude možné zapojit takovou míru automatizace jako u
… více »Firefox pro iOS přichází s integrovaným blokováním reklam. Funkce je ve výchozím nastavení vypnutá a lze ji aktivovat v Settings > Browsing > Ad Blocker.
Společnost Hugging Face ve spolupráci se společností Pollen Robotics představila (𝕏) open-source robota Microduck. Předobjednat jej lze za 340 eur.
Open-source autonomní AI agent OpenClaw (Wikipedie) byl vydán ve verzi 2026.8.1 aneb 2.0. Přehled novinek v poznámkách k vydání.
Byla vydána první veřejná preview verze PrusaSliceru 3.0. Přesně 15 let po zveřejnění první verze Slic3ru, které připadlo na 1. září 2011. Jedná se o dosud největší upgrade PrusaSliceru: "Řídili jsme se tím, co skutečně potřebujete, a tak jsme například zcela zahodili stávající uživatelské rozhraní a vytvořili ho znovu od nuly. Přinášíme také nový systém projektů, kompletně přepracované profily navržené pro moderní tiskárny s větším
… více »Byl vydán Mozilla Firefox 155.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Vypíchnout lze Smart Window, zatím ale dostupné pouze pro uživatele v USA, Kanadě a Francii. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 155 bude brzy k dispozici také na Flathubu a Snapcraftu.
Tima Cooka na pozici generálního ředitele společnosti Apple dnešním dnem nahradil John Ternus, který byl dosud odpovědný za hardware. Tim Cook vedl Apple od roku 2011, kdy funkci převzal od později zesnulého spoluzakladatele společnosti Stevea Jobse. Za 15 let v čele Applu více než zdvojnásobil tržní hodnotu firmy.
Organizátoři konference LinuxDays ukončil veřejné přihlašování přednášek. Teď je na vás, abyste vybrali nejlepší témata pro letošní ročník. Hlasovat můžete do pondělí 7. září, poté bude podle výsledků hlasování sestaven program pro letošní ročník.
Servo, engine webového prohlížeče napsaný v Rustu, byl vydán ve verzi 0.5.0. Novinky shrnuje přehled projektu za červenec. Došlo k dalšímu pokroku ve vykreslování webových stránek. Současným cílem projektu je vytvořit komponentu webového prohlížeče jako WebView pro použití v jiných aplikacích.
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".