Vlákno názorů k článku KolibriOS: kolibří systém v 5 MB od JS - Jako programator v assembleru (byt na mainframu) prihodim svuj...

  • Článek je starý, nové názory již nelze přidávat.
  • 21. 1. 2010 9:18

    JS (neregistrovaný)

    Jako programator v assembleru (byt na mainframu) prihodim svuj nazor. Ono je pomerne snadne napsat nejaky software, ktery je na prvni pohled rychlejsi nez systemy stavajici (a pokud ho budete psat v assembleru, pravdepodobne to tak dopadne).

    Ovsem rychle narazite, pokud budete pak skutecne chtit implementovat veskerou funkcionalitu systemu, ktere se snazite kopirovat. A to bude problem i v pripade, kdy pujde o vyssi jazyk; v zasade budete kopirovat historii soucasnych systemu, ktere byly nekolikrat prepsany, casto za ucelem zvyseni vykonu.

    Navic, assembler do toho vnasi dalsi problemy. Programy v nem nelze snadno refaktorovat (je to write-only jazyk), a pokud to zacnete delat, ztratite velkou cast puvodniho vykonu. Navic efektivni programy v assembleru jsou casto efektivni za cenu modularity, a pokud se tam tu modularitu pokusite dodat, zase skoncite se ztratou vykonu. V assembleru se take obtizne implementuji komplikovanejsi algoritmy, coz je zase potencialne ztrata vykonu. A to nemluvim o tom, ze dnesni prekladace jsou uz lepsi nez prumerny programator.

    Vykon assembleru je navic zavisly na architekture procesoru; instrukce a zpusob psani efektivni pred 10–15 lety uz dnes efektivni neni (a to je ten lepsi pripad, kdy pouzivate instrukcni sadu pro stale zivy procesor).

    Takze, abych to shrnul. Jasne, ze to startuje za 3s, protoze je to neobecne a nemodularne napsane, a neumi to tolik co soucasne desktopy. Podle me jsou to zkratka silenci, a prakticky vyznam to zadny nema (i kdyz naprosto chapu poetiku takoveho pocinu, kdyz jsem zacinal u nas ve firme, taky jsem chtel mit vsechno v mainframe assembleru).

  • 21. 1. 2010 10:05

    mixal (neregistrovaný)

    Je pravda, ze pokial programator chape tomu ako funguje pocitac programuje napr v C++ s tym, ze ma aspon pribliznu predstavu ako vyzera prelozeny kod, tak vacsinou kod nema moc daleko od toho aby bol optimalny.

  • 21. 1. 2010 10:51

    j. (neregistrovaný)

    Problem je aj medzi jednotlivymi generaciami procesorov rovnakej architektury – kod v asembleri napisany pre netburst procesory ma daleko k optimalnosti na nehalem nebo k8.
    Kod napisany vo vyssom jazyku sa pre danu architekturu prelozi znova, sice pravdepodobne suboptimalne, ale stale v akceptovatelnej kvalite a za neporovnatelnu ce­nu.

  • 21. 1. 2010 12:07

    sadfasfa (neregistrovaný)

    jsou to borci a ted kdyz tak skvele vidi do assembleru by meli zacit svuj system refaktorovat a co jde prepsat co C. pak by to mohla byt zajimava aktivita i z sirsiho pohledu.

  • 21. 1. 2010 14:05

    beer (neregistrovaný)

    Souhlasim temer ve vsech bodech, ale rozhodne odmitam, ze dnesni prekladace jsou lepsi nez prumerny programator. Vetsina programatoru v assembleru dokaze napsat rychlejsi kod nez jakykoliv prekladac. Rozhodne se to ale nevyplati.

  • 21. 1. 2010 16:15

    ondra.novacisko.cz (neregistrovaný)

    O tom se budu hádat. Průměrný programátor nedokáže v hlavě uložit vztahy mezi části programu jedné trošku složitější šablony a to co překladač vyrobí za několik sekund, on bude navrhovat několik dní. Možná nakonec bude programátor lepší (překladač se neučí s chyb), ale za jakou cenu.

  • 21. 1. 2010 16:39

    Bilbo (neregistrovaný)

    Proto se taky v assembleru pisou jen nektere casti, predevsim na vykon pomerne kriticke casti (jadra ruznych kodeku audia a videa, sifrovaci algoritmy, …), kde zrychleni treba o 20% je celkem dost pak v praxi znat a ke kterym casto lze pouzit nejake specialni instrukce (napr. instrukce pro AES u procesoru VIA) a vyrazne tak dany kod urychlit.

  • 21. 1. 2010 18:57

    Zdenek -

    Přesně tak, překladač nikdy nepochopí, jak to člověk myslel. Tuhle jsem potřeboval na všechny bajty v souboru provést
    rol [bajt], 2
    Ve „vyšším“ jazyce jsem tedy číslo bajtu převedl na 16bitový integer, vynásobil 4, udělal pár masek AND a zbytek po dělení 256…
    No a kód exáče se nafoukl o 20 kB!!! O pomalosti nemluvě.
    Nezpochybňuji tady ekonomickou stránku vývoje aplikací, ale kompiler si může o rychlosti kódu od člověka nechat jen zdát.
    Kdybych byl autor softwaru, který si klade ambice být rychlý, volil bych hybridní přístup – horká místa v ASM a zbytek v něčem blbovzdorném. A hlavně by se mělo dát volit, jestli se budou při každém volání funkce tyto kopírovat jinam do paměti (a dokonce relokovat), nebo se to zaonačí zásobníkem, což obvykle stačí a je to daleko úspornější.

  • 21. 1. 2010 20:37

    klusacek (neregistrovaný)

    Ja myslim ze zalezi na problemu. Ony prekladace to nemaji tak snadne, lecjaka informace v kodu chybi (treba vite ze nejaka funkce dostava argument vzdy nenulovy, ale kdyz ji kompilujete do knihovny tak jeste nemate vsechna jeji volani aby kompilator mohl neco takoveho odvodit – z toho duvodu se pak treba nekde uvnitr nevyoptimalizuje if). Nebo ta informace treba i ve zdrojaku je, ale slozite ji odvodit, takze se to nedela. Nebo je to neco vagniho, jako v takovych pripadech, kdy treba clovek zna typickou velikost vstupu. To pak s pomerne malou namahou muze napsat lepsi kod v ASM.

    Ovsem architektura dnesnich CPU je takova ze lidem, resp. jejich dusevnimu zdravi moc nepreje. Jednak kdyz mate superskalarni CPU tak porad abyste pocital latence instrukci a jake mate vyuzit jednotek, atd. Druha vec je vyuziti cachi. Koukne na http://en.wikipedia.org/wiki/Polytope_model at vidite co treba se snazi delat gcccko. V kombinaci s http://en.wikipedia.org/wiki/Loop_tiling to muze nektere vypocty mnohonasobne zrychlit.

    Jestli znate nejakeho prumerneho ASM programatora, ktery tohle dela rucne, tak ho rad taky poznam.

  • 22. 1. 2010 6:47

    ondra.novacisko.cz (neregistrovaný)

    V tomhle je nejlepší překladač o informace neochuzovat. Ideálně je templatové nebo inlinové programování. Překladač má k dispozici všechny informace, včetně obsahů funkcí, může se rozhodnout, zda kód nechá ve funkci, nebo jí inlinuje, může si přeházet registry jak potřebuje, protože vidí do funkcí, ví, které registry se budou měnit. Jediný, co mi v současných překladačích chybí je určování četností podmínek, něco jako, „tahle podmínka nastává výjimečně“. Trošku se to řeší přes výjimky, tedy test na chybu se provede jen jednou a zbytek řeší výjimka mimo hlavní scope. Ale ideální to není, protože výjmky jsou tak náročné, že se hodí spíš pro vyjádření „tahle podmínka skoro nenastává“.

    Jinak vývoj v překladačích pokračuje, dopředu jde jak GCCčko, tak Microsoft Visual Studio. Optimalizuje se všude, nelze tedy program psát s tím, že dopředu vím, jak se která konstrukce přeloží. Možná dneska, za rok už to může být jinak. Tak nad tím nepřemýšlím, maximálně to řeším v časově kritických částechm a těch je málo (jsou to extrabuřty, speciality). K tomu navíc pomáhají různé profiléry, napříkla MSVC nabízí profilér podmínek … což řeší částečně to co jsem psal nahoře… podmínky se pak překládaji z ohledem na to, které větve byly pravděpodobnější. Dále je to třeba Whole Program Optimizator, který provádí optimalizace při linkování, takže ta poznámka o tom, že překladač nevidí do knihoven nemusí úplně platit. Jisté optimalizace se provádí napříč celým kódem (MSVC).

    Atd, atd. Proto preferuju C/C++, ten pokrok v optimalizacích je vysoký, a troufám si tvrdit, že jakékoliv frameworky, ať už jde o Javu, nebo .NET navzdory tomu, že mezikód překládají do nativní formy, nebudou mít nikdy k dispozici tolik informací, kolik lze vytěžit přímo ze zdrojáků. A taky jsem už slyšel, že JITcompilery využívají runtime informace a optimalizují vůči něm… jenže tomu zas tolik nevěřím, protože JITC je náročná operace, kterou nelze provádět pokaždé, když se runtime informace změní.

  • 22. 1. 2010 10:59

    mixal (neregistrovaný)

    zaujimave veci

    ta cetnost podmienok by bola fakt super pre prekladace, zaujimave ze MS to este nepridal

  • 22. 1. 2010 13:28

    ondra.novacisko.cz (neregistrovaný)

    Ne, ono to tam je, ale přes profiler. Člověk to nemůže specifikovat v programu, ale musí přes profiler. Ale nezkoušel jsem to.

  • 22. 1. 2010 15:44

    KarelI

    > frameworky, ať už jde o Javu, nebo .NET nebudou mít nikdy k dispozici tolik informací, kolik lze vytěžit přímo ze zdrojáků

    V tomhle nemate pravdu. Konkretne JVM ma k dispozici bytecode, ktery se hodne podoba puvodnimu zdrojaku, ale navic vidi i do runtime. Sun JVM dela optimalizace i na zaklade hodnot promennych, ktere prijdou zvenku, to zadny prekladac samozrejme mit nemuze.
    Delal jsem si jednoduchy test, kde jsem na zaklade random hodnoty zalozil implementaci interfacu a tu jsem porad dokola volal. V C++ to trvalo asi 20× dele nez v jave. Coz je dukaz, ze JIT kompiler se muze za behu podivat co mu prislo za tridu a inlinovat volani jejich metod (a taky to dela), v c++ to samozrejme nelze pokud kompiler neodvodi jakou ma instanci.

  • 22. 1. 2010 23:06

    ondra.novacisko.cz (neregistrovaný)

    No nevím, co jste dělal za test, asi by to chtělo napsat o tom článek. Nezdá se mi, že by JIT byl 20× rychlejší než nativní C++. Volání virtuální metody je „pouhý“ call podle adresy v paměti. Nic co by se nedalo proudově zpracovat (notabene, když se ta adresa po celou dobu programu nemění).

    Inlinovat funkce pomůže v řádově procent, vy ale mluvíte o navýšení o 2000%. I kdyby JIT volání funkcí (vlastně virtuálně) inlinovál, například v cyklech, pak jste schopen být rychlejší dejme tomu o těch pár procent. Otázkou je, kolik času stojí vlastní spuštění JITu. Určitě lze najít speciální případ, kdy mám pět interfaců, které náhodně volám milionkrát. Ale tyhle speciální případy buď nenastávají, nebo v časově kritických částí se řeší přes šablny, čili vlastně podobně jako to dělá JIT. Akorát se to přepřeloží dopředu, pro všechny možné varianty, které mohou nastat.

  • 23. 1. 2010 0:49

    KarelI

    Napsal jsem jednoduchy lowlevel test. Interface s metodami void add(), void add(int), 2 implementace, kazda do member promenne pricita nejake konstantni cislo, funkce

    void count(Iface * p) {
      for (int i = 0; i < 1000000000; i++)
        p->add();
    }


    Zalozil jsem instance a,b tech trid a dostal jsem tyto vysledky:
    nahodne vybrani a nebo b a 3× volani count s add()
    JIT 0.5s
    c++ 10s

    to same s addX(nahodna konstanta)
    JIT 0.56s
    c++ 13s

    to same s addX(i)
    JIT 2.2s
    c++ 13s

    jednou count s add()
    java bez JIT 14s

    Zaver – JIT dokaze za behu inlinovat virtualni metody, kdyz je vnitrek cyklu konstantni, tak ho dokaze i „rozbalit“. Jakykoli prekladac do nativu nema sanci, pokud si to nemuze vyhodnotit behem prekladu.
    Samozrejme je to extremni pripad, ale jako reakce na „JIT nemuze…“ to myslim staci.
    Pro me to znamena, ze se muzu klidne zabyvat navrhem a OOP v jave a nemusim delat nejake kompromisy v c++ aby to nebylo pomale. Kdyz navic vezmu v uvahu GC, ktery mi usetri dalsi praci a ve slozitejsich aplikacich je rychlejsi nez new/delete, tak je volba jasna :-)

  • 23. 1. 2010 13:09

    KarelI

    > A nezapoměl jste v C++ zapnout optimalizace? :-D

    To je tak tezke tomu uverit? :-)

    Delal jsem to v msvc, zkousel jsem zapinat vsechno mozne, ale myslim, ze on proste nic moc optimalizovat nemuze. Jelikoz to je virtualka, tak nanejvys chodit primo na adresu funkce, ale inlinovat nemuze. Takze volani, soucet, return, i++ mi 3e9 krat za 10s prijde dobre. Mam notas 2GHz Pent. M, takze to zhruba vychazi na 7taktu/cyklus

    Kdyz tam volam to same nevirtualne, tak je to samozrejme hned.

  • 23. 1. 2010 10:22

    JS (neregistrovaný)

    A pokud jste zkousel zapnout optimalizace, co to zkusit jeste (v GCC) s -fprofile-use (a spol.)?

    Jeste -fwhole-program by mohlo pomoct.

  • 24. 1. 2010 23:11

    tom (neregistrovaný)

    Myslím že vypovídací hodnota toho je, že v tom cyklu zabere dereferencování pointeru na virtuální metodu víc času než tělo metody add. Což neznamená nic, pokud není řečeno, co ta metoda add() uvnitř dělá. Nesjpíš (skoro) nic, což ale není zrovna typický program, že…

  • 24. 1. 2010 23:25

    KarelI

    Vypovidaci hodnota je, ze JIT se dokaze zbavit virtualni metody a ze ma tedy vice informaci nez prekladac c++, na coz jsem reagoval. Priklad byl samozrejme volen tak, aby to bylo zrejme.

  • 25. 1. 2010 1:00

    ondra.novacisko.cz (neregistrovaný)

    Dereferencování pointeru stojí jeden takt. Skok do podprogramu taky stojí jeden takt. Důležitý je obsah funkce. Pokud je tam typický funkční framework, tak se tam zbytečně vyplácá několik desítek taktů na vstup do funkce výstup z funkce. Proto jsou důležité optimalizace, které umí tenhle běžný funkční prolog a epligo úplně vyhodit.

    Ano uznávám, že tady bude C++ hloupější, protože obě části kódu neví, s kým mají na druhé straně čest.

    Na druhou stranu, jak efektivní vlastně JIT bude. Dejme tomu, že dokáže optimálně přeložit funkci se známým parametrem. Okaj, co se stane s tím kódem? Uloží se někam do cache? co když se bude zase potřebovat? Jak velká ta cache je? Co když těch rozhranní budu mít 100. Co funguje na jednom malém příkladu dobře nebude fungovat na příkladu o level výše.

    Možná vás taky JIT vypekl. Zjistil, že výsledkem operace je konstanta a místo fyzického provedení kódu nahradil kód výsledkem. Vy to ale nevíte a pravděpodobně nezjistíte. Těch půl sekundy ve skutečnosti zabrala práce JITu.

    Jako na každý jazyk lze najít konstrukci, kde je rychlejší, než ostatní jazyky. Zrovna na Javě můžete machrovat, pokud do cyklu přidáte jediné new. C++ určitě bude pozadu, zatímco Java poběží jako ďábel… Dokud se na to nevrhne GC. Potom už to nemusí být tak zřejmé.

    Jako programátor v C++ znám cenu každé operace. V Javě si nikdy nejsem jist, jestli tahle část poběží rychle nebo pomalu. Několikrát jsem psal aplikaci, kde byly nějaké animace. Několikrát jsem řešil jejich občasné poskakování. V C++ nic takového nepozorováno.

    Tím chci říct, že Java hodně těží z toho, že 80% času běží 20% kódu. Tam se JIT zřejmě dobře chytne. Ale na „velkých“ aplikací bude stále pomalejší. Vemte si třeba Eclipse. Žrout času i prostoru. Bohužel není s čím moc srovnávat, ale třeba s MSVC6, který byl ještě v C++ (MSVC Expressy jsou .NET), a rychlost nejzákladnější věcí toho editoru je úplně někde jinde.