Keresés

Hirdetés

Új hozzászólás Aktív témák

  • emvy

    nagyúr

    válasz bajnokpityu #82128 üzenetére

    Oke, elso korben az assembly/C problematika, nagyon leegyszerusitve, hifitopikba :)

    A programozas vegulis arrol szol, hogy van egy problemad, amit valamilyen modon formalisan megfogalmazol. A megfogalmazas sokfele 'nyelven' tortenhet, vannak magasabb es alacsonyabb szintu nyelvek. Legyen mondjuk a problema az, hogy invertalni akarsz egy matrixot. A cel az, hogy egy adott matrixbol a vegen egy inverz matrix keletkezzen. Az, hogy mitol invertalodik a matrix, az mindegy, a cel a matematikai korrektseg es a minel nagyobb teljesitmeny. A processzoroknak van egy 'programozasi nyelve', amit altalanosabb modon ISA-nak szoktak hivni. Ez a PC-ken az amd64/x86. A processzorok belul ezt atforditjak implementacio-fuggo mikrokodra. Tehat egy adott 'assembly' utasitas mas mikrokodra fordul egy Ryzen es egy i7 eseteben, szoval az assembly egyaltalan nem a leheto legalacsonyabb szintu

    Tehat a lanc tele van forditokkal:
    - a programozo fordit a megrendelo es a magasszintu programnyelv kozott
    - a compiler a magasszintu nyelv es assembly kozott
    - a processzor fordit az assembly es a mikrokod kozott

    Akkor erdemes atugrani egy lepest, ha ugy gondoljuk, hogy mi tobbet tudunk az eggyel lentebbi szintrol, mint a fordito (a fejlesztes sebesseget most hagyjuk). Tehat ha pl. a megrendelo egy matematikus, akkor sajat maga is megprobalhatja lekodolni a programot, de lehet, hogy nem erdemes, mert a programozo tudja, hogy milyen eszkozokkel lehet a legjobb vegeredmeny elerni. Ugyanigy: a programozo kihagyhatja a magasszintu nyelvet, ha ugy gondolja, hogy o jobban ismeri az alacsonyabb szinteket (mikrokod, CPU architektura) mint a programozo.

    A helyzet az, hogy azert nem szokas atugrani a forditokat megsem, mert altalaban nincs olyan ember, aki vilagszinvonalon ertene a sajat domenjehez es az alatta levo reszhez is. Tehat egy matematikus nem lesz kepben azzal kapcsolatban, hogy elozo honapban milyen valtozasok tortentek a Rust standard library-ben. Ugyanugy egy programozo sem fogja elolrol-hatulrol ismerni az osszes aprosagot a CPU architekturakkal kapcsolatban.

    Ezenkivul meg valami nehezites, es ez nagyon fontos: az, hogy hiaba ismered valaminek a felepiteset, ha az tul bonyolult ahhoz, hogy atlasd. Pelda: AlphaGo. Mindenki tudja, hogy mik a Go szabalyai, ennek ellenere a szamitogep mar megver minket. Raadasul azt se tudjuk, hogy ver meg minket. Ennek analogiajara: ahogy bonyolodnak a processzorok, ugy lesz egyre lehetetlenebb 'mindenre gondolni'.

    Tehat az elso oka annak, hogy a kezzel irt assembly szinte soha nem gyorsabb, mint a C ekvivalens az az, hogy nem fogsz olyan asm kodot irni, ami annyira szofisztikalt, mint amit egy fordito le tud gyartani. Volt errol egy jo cikk nemreg, az illeto szenne optimalizalta az asm kodjat, es a C fordito 2%-al gyorsabb kodot generalt, mert megsaccolta, hogy hogyan erdemes ures utasitasokat (!) es elso ranezesre lassabb operaciokat berakni az asm kodba ahhoz, hogy a CPU pipelineok meg a branch predictor optimalishoz kozelebbi modon mukodjon.

    A masik oka annak, hogy neha a magasszintu programnyelvek jobban mukodnek, az az, hogy amikor leirod, hogy x = a*b + c*d, akkor az nem ekvivalens azzal, hogy
    x1 = a*b
    x2 = c*d
    x= x1+x2
    .. mert ez utobbi verzioban van egy sorrendezes. Az asm -> mikrokod fordito nem fogja 100%-osra tudni, hogy miert ilyen sorrendben van az elso es a masodik szorzas (ez rossz pelda, mert egyebkent a CPUk ezt mar ujrarendezik), tehat feltetelezheti, hogy van valami oka annak, hogy miert igy nez ki a kod. Az elso peldat 'elolvasva' a C -> asm fordito tudja, hogy te mit akarsz csinalni, igy nyugodtan ujrarendezheti az egeszet ugy, ahogy szerinte optimalis a processzor szempontjabol. Osszefoglalva: alacsonyabb szintu nyelvet hasznalva akaratlanul is 'tulspecifikalhatod' a kodot, es nem hagysz helyet az okosabb automatizalt optimalizacionak.

    A harmadik resz nem igazan a C-re vonatkozik, hanem pl. a Java-ra es hasonlo runtime forditott nyelvre. Van egy ilyen kod:
    if a is true
    fetch data from memory address X and multiply by Z;
    else
    fetch data from memory address Y and multiply by W;

    Namost adatot behuzni X vagy Y cimrol mondjuk 500 orajelciklus. Ha tudjuk elore, hogy 'a' most igaz vagy hamis lesz, akkor elore el tudjuk kezdeni behuzni X-et vagy Y-t. Ez viszont sok mindentol fugg, es ez lehet, hogy csak runtime derul ki.
    Osszefoglalva ezt a pontot: kezzel optimalizalni nem feltetlenul lehetseges anelkul, hogy a ismerned _konkret_ adatokat, amivel a program epp fut. (Ld. Turing tetel egyebkent.)

    Nagyon ritkan, nagyon-nagyon specialis esetekben elofordulhat, hogy valaki tud kezzel optimalizalni a fordito altal generalt kodon. Ez gyakorlatban szinte sosem fordul elo, es egeszen tapasztalt ASM magusok is meglepoen szoktak tapasztalni, hogy a fordito jobb, mint amit ok irtak. Ezenkivul a lenyeges teljesitmenynovekedes szinte mindig algoritmikus valtoztatasokkal jon.

    while (!sleep) sheep++;

Új hozzászólás Aktív témák