Vláda Spojených států získala desetiprocentní podíl v americkém výrobci čipů Intel. Oznámili to podle agentur americký prezident Donald Trump a ministr obchodu Howard Lutnick. Společnost Intel uvedla, že výměnou za desetiprocentní podíl obdrží státní dotace v hodnotě 8,9 miliardy dolarů (zhruba 186 miliard Kč). Částka podle Intelu zahrnuje dříve přislíbené subvence 5,7 miliardy dolarů z programu CHIPS na podporu výroby čipů v USA,
… více »Organizace Apache Software Foundation (ASF) vydala verzi 27 integrovaného vývojového prostředí a vývojové platformy napsané v Javě NetBeans (Wikipedie). Přehled novinek na GitHubu. Instalovat lze také ze Snapcraftu a Flathubu.
Knihovna FFmpeg byla vydána ve verzi 8.0 „Huffman“. Přibyla mj. podpora hardwarově akcelerovaného kódování s využitím API Vulcan, viz seznam změn.
Národní úřad pro kybernetickou a informační bezpečnost (NÚKIB) vydal Zprávu o stavu kybernetické bezpečnosti ČR za rok 2024 (pdf). V loňském roce NÚKIB evidoval dosud nejvíce kybernetických bezpečnostních incidentů s celkovým počtem 268. Oproti roku 2023 se však jedná pouze o drobný nárůst a závažnost dopadů evidovaných incidentů klesá již třetím rokem v řadě. V minulém roce NÚKIB evidoval pouze jeden velmi významný incident a významných incidentů bylo zaznamenáno 18, což oproti roku 2023 představuje pokles o více než polovinu.
Byl publikován aktuální přehled vývoje renderovacího jádra webového prohlížeče Servo (Wikipedie). Servo mimo jiné nově zvládne animované obrázky APNG a WebP.
Na chytré telefony a počítačové tablety v Rusku bude od začátku příštího měsíce povinné předinstalovávat státem podporovanou komunikační aplikaci MAX, která konkuruje aplikaci WhatsApp americké společnosti Meta Platforms. Oznámila to dnes ruská vláda. Ta by podle kritiků mohla aplikaci MAX používat ke sledování uživatelů. Ruská státní média obvinění ze špehování pomocí aplikace MAX popírají. Tvrdí, že MAX má méně oprávnění k přístupu k údajům o uživatelích než konkurenční aplikace WhatsApp a Telegram.
Společnost PINE64 stojící za telefony PinePhone nebo notebooky Pinebook publikovala na svém blogu srpnový souhrn novinek. Kvůli nedostatečnému zájmu byla ukončena výroba telefonů PinePhone Pro.
Po pěti měsících vývoje byla vydána nová verze 0.15.1 programovacího jazyka Zig (GitHub, Wikipedie). Verze 0.15.0 byla přeskočena. Přispělo 162 vývojářů. Přehled novinek v poznámkách k vydání.
Před sedmi lety společnost Valve představila fork projektu Wine s názvem Proton umožňující v Linuxu přímo ze Steamu hrát počítačové hry do té doby běžící pouze ve Windows. Aktuální přehled podporovaných her na stránkách ProtonDB
Společnost DuckDuckGo rozšířila svůj AI chat Duck.ai o GPT-5 mini (𝕏). Duck.ai umožňuje anonymní přístup bez vytváření účtů k několika modelům umělé inteligence. Aktuálně k GPT-4o mini, GPT-5 mini, Llama 4 Scout, Claude Haiku 3.5 a Mistral Small 3.
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.
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í (
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,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 listPodľa môjho testu:
List.map
. Pro OCaml jsou nějaká měření v článku Optimizing List.map.
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".