Upea haastattelu Cliff Clickin, Java-kielisen JIT-kokoelman isän, kanssa

Upea haastattelu Cliff Clickin, Java-kielisen JIT-kokoelman isän, kanssaCliff Click — Cratuksen teknologiajohtaja (IoT-anturit prosessien parantamiseen), useiden startup-yritysten (mukaan lukien Rocket Realtime School, Neurensic ja H2O.ai) perustaja ja perustaja, joilla on useita onnistuneita irtautumisia. Cliff kirjoitti ensimmäisen kääntäjänsä 15-vuotiaana (Pascal TRS Z-80:lle)! Hänet tunnetaan parhaiten työstään C2:lla Javassa (Solmumeri IR). Tämä kääntäjä osoitti maailmalle, että JIT pystyi tuottamaan korkealaatuista koodia, mikä oli yksi tekijöistä Javan syntymiselle yhdeksi tärkeimmistä nykyaikaisista ohjelmistoalustoista. Sitten Cliff auttoi Azul Systemsiä rakentamaan 864-ytimisen keskuskoneen puhtaalla Java-ohjelmistolla, joka tuki GC-taukoja 500 gigatavun kasassa 10 millisekunnissa. Yleisesti ottaen Cliff onnistui työstämään kaikkia JVM:n näkökohtia.

 
Tämä habrapost on loistava haastattelu Cliffille. Puhumme seuraavista aiheista:

  • Siirtyminen matalan tason optimointiin
  • Kuinka tehdä suuri refaktorointi
  • Kustannusmalli
  • Matalan tason optimointikoulutus
  • Käytännön esimerkkejä suorituskyvyn parantamisesta
  • Miksi luoda oma ohjelmointikieli
  • Performance Engineerin ura
  • Tekniset haasteet
  • Hieman rekisterin allokoinnista ja moniytimistä
  • Elämän suurin haaste

Haastattelun suorittaa:

  • Andrei Satarin Amazon Web Services -palvelusta. Uransa aikana hän onnistui työskentelemään täysin erilaisissa projekteissa: hän testasi NewSQL-hajautettua tietokantaa Yandexissa, pilvitunnistusjärjestelmää Kaspersky Labissa, moninpeliä Mail.ru:ssa ja valuuttakurssien laskentapalvelua Deutsche Bankissa. Kiinnostaa testata laajamittaisia ​​taustajärjestelmiä ja hajautettuja järjestelmiä.
  • Vladimir Sitnikov Netcrackerilta. Kymmenen vuotta työtä NetCracker OS:n suorituskyvyn ja skaalautuvuuden parissa. Ohjelmisto on teleoperaattoreiden käyttämä verkko- ja verkkolaitteiden hallintaprosessien automatisointiin. Kiinnostunut Java- ja Oracle Database -suorituskykyongelmista. Yli tusinan virallisen PostgreSQL JDBC -ohjaimen suorituskykyparannuksen kirjoittaja.

Siirtyminen matalan tason optimointiin

Andrew: Olet iso nimi JIT-kokoelman, Javan ja yleensä suorituskykytyön maailmassa, eikö niin? 

Cliff: Niin se on!

Andrew: Aloitetaan muutamalla yleisellä kysymyksellä suoritustyöstä. Mitä mieltä olet valinnasta korkean ja matalan tason optimointien välillä, kuten työskentely prosessoritasolla?

Cliff: Kyllä, täällä kaikki on yksinkertaista. Nopein koodi on se, joka ei koskaan toimi. Siksi sinun on aina aloitettava korkealta tasolta, työskenneltävä algoritmien parissa. Parempi O-merkintä päihittää huonomman O-merkinnän, elleivät jotkin riittävän suuret vakiot puutu asiaan. Matalat asiat jäävät viimeiseksi. Tyypillisesti, jos olet optimoinut loput pinostasi tarpeeksi hyvin ja mielenkiintoista tavaraa on vielä jäljellä, se on matala taso. Mutta miten aloittaa korkealta tasolta? Mistä tietää, että korkeatasoista työtä on tehty tarpeeksi? No... ei mitenkään. Ei ole olemassa valmiita reseptejä. Sinun on ymmärrettävä ongelma, päätettävä mitä aiot tehdä (jotta et ryhdy tarpeettomiin toimenpiteisiin tulevaisuudessa) ja sitten voit paljastaa profiloijan, joka voi kertoa jotain hyödyllistä. Jossain vaiheessa huomaat itsekin, että olet päässyt eroon tarpeettomista asioista ja on aika tehdä matalan tason hienosäätöä. Tämä on ehdottomasti erityinen taiteen laji. Monet ihmiset tekevät tarpeettomia asioita, mutta liikkuvat niin nopeasti, ettei heillä ole aikaa huolehtia tuottavuudesta. Mutta tämä on siihen asti, kunnes kysymys herää suoraan. Yleensä 99% ajasta kukaan ei välitä siitä, mitä teen, kunnes se hetki, jolloin kriittiselle tielle tulee tärkeä asia, josta kukaan ei välitä. Ja täällä kaikki alkavat nalkutella sinua "miksi se ei toiminut täydellisesti alusta alkaen". Yleisesti ottaen suorituskyvyssä on aina jotain parannettavaa. Mutta 99 % ajasta sinulla ei ole liidejä! Yrität vain saada jotain toimimaan ja prosessin aikana ymmärrät, mikä on tärkeää. Et voi koskaan tietää etukäteen, että tämän kappaleen on oltava täydellinen, joten itse asiassa sinun on oltava täydellinen kaikessa. Mutta tämä on mahdotonta, etkä tee sitä. Aina on paljon korjattavaa - ja se on täysin normaalia.

Kuinka tehdä suuri refaktorointi

Andrew: Miten työskentelet esityksen parissa? Tämä on monialainen ongelma. Oletko esimerkiksi koskaan joutunut käsittelemään ongelmia, jotka johtuvat monien olemassa olevien toimintojen risteyksestä?

Cliff: Yritän välttää sitä. Jos tiedän, että suorituskyky on ongelma, ajattelen sitä ennen koodauksen aloittamista, erityisesti tietorakenteiden suhteen. Mutta usein huomaat kaiken tämän vasta myöhemmin. Ja sitten sinun on mentävä äärimmäisiin toimenpiteisiin ja tehtävä se, mitä kutsun "uudelleenkirjoita ja valloittaa": sinun täytyy napata tarpeeksi suuri pala. Osa koodista on silti kirjoitettava uudelleen suorituskykyongelmien tai jonkin muun vuoksi. Olipa koodin uudelleenkirjoituksen syy mikä tahansa, on melkein aina parempi kirjoittaa suurempi osa uudelleen kuin pienempi pala. Tällä hetkellä kaikki alkavat vapisemaan pelosta: "Voi luoja, et voi koskea niin paljon koodia!" Mutta itse asiassa tämä lähestymistapa toimii melkein aina paljon paremmin. Sinun on välittömästi tartuttava suureen ongelmaan, piirrettävä sen ympärille iso ympyrä ja sanottava: Kirjoitan uudelleen kaiken ympyrän sisällä. Reuna on paljon pienempi kuin sen sisällä oleva sisältö, joka pitää vaihtaa. Ja jos tällainen rajojen määrittely antaa sinun tehdä työn sisällä täydellisesti, kätesi ovat vapaat, tee mitä haluat. Kun ymmärrät ongelman, uudelleenkirjoitusprosessi on paljon helpompaa, joten pure isosti!
Samaan aikaan, kun kirjoitat suuren uudelleen ja ymmärrät, että suorituskyky tulee olemaan ongelma, voit heti alkaa huolehtia siitä. Tämä muuttuu yleensä yksinkertaisiksi asioiksi, kuten "älä kopioi tietoja, hallitse tietoja mahdollisimman yksinkertaisesti, tee siitä pieni". Suurissa uudelleenkirjoituksissa on tavallisia tapoja parantaa suorituskykyä. Ja ne melkein aina pyörivät datan ympärillä.

Kustannusmalli

Andrew: Yhdessä podcastissa puhuit kustannusmalleista tuottavuuden yhteydessä. Voitko selittää mitä tarkoitit tällä?

Cliff: Varmasti. Synnyin aikakauteen, jolloin prosessorin suorituskyky oli erittäin tärkeää. Ja tämä aikakausi palaa jälleen - kohtalo ei ole ilman ironiaa. Aloin elää kahdeksanbittisten koneiden aikoja; ensimmäinen tietokoneeni toimi 256 tavulla. Juuri tavuja. Kaikki oli hyvin pientä. Ohjeet piti laskea, ja kun aloimme siirtyä ohjelmointikielipinossa ylöspäin, kielet valtasivat yhä enemmän. Siellä oli Assembler, sitten Basic, sitten C, ja C hoiti paljon yksityiskohtia, kuten rekisterin allokoinnin ja ohjeiden valinnan. Mutta kaikki oli siellä melko selvää, ja jos laittaisin osoittimen muuttujan esiintymään, niin saan kuorman, ja tämän ohjeen hinta on tiedossa. Laitteisto tuottaa tietyn määrän konesyklejä, joten eri asioiden suoritusnopeus voidaan laskea yksinkertaisesti laskemalla yhteen kaikki ajettavat käskyt. Jokainen vertailu/testaus/haara/soitto/lataus/myymälä voitaisiin laskea yhteen ja sanoa: se on sinun suoritusaikasi. Kun työskentelet suorituskyvyn parantamiseksi, kiinnität ehdottomasti huomiota siihen, mitkä numerot vastaavat pieniä kuumia jaksoja. 
Mutta heti kun vaihdat Javaan, Pythoniin ja vastaaviin asioihin, siirryt hyvin nopeasti pois matalan tason laitteistosta. Paljonko getterin soittaminen Javassa maksaa? Jos JIT HotSpotissa on oikein upotettu, se latautuu, mutta jos se ei tehnyt tätä, se on funktiokutsu. Koska puhelu on kuumassa silmukassa, se ohittaa kaikki muut kyseisen silmukan optimoinnit. Siksi todelliset kustannukset ovat paljon korkeammat. Ja menetät välittömästi kyvyn tarkastella koodinpätkää ja ymmärtää, että meidän pitäisi suorittaa se prosessorin kellonopeuden, muistin ja käytetyn välimuistin suhteen. Kaikesta tästä tulee mielenkiintoista vain, jos todella pääset esitykseen.
Nyt olemme tilanteessa, jossa prosessorinopeudet eivät ole juurikaan nousseet kymmeneen vuoteen. Vanhat ajat ovat palanneet! Et voi enää luottaa hyvään yksisäikeiseen suorituskykyyn. Mutta jos yhtäkkiä alat käyttää rinnakkaislaskentaa, se on uskomattoman vaikeaa, kaikki katsovat sinua kuin James Bondia. Kymmenkertaiset kiihtyvyydet tapahtuvat yleensä paikoissa, joissa joku on sotkenut jotain. Samanaikaisuus vaatii paljon työtä. Saadaksesi XNUMX-kertaisen nopeuden, sinun on ymmärrettävä kustannusmalli. Mitä ja kuinka paljon maksaa? Ja tehdäksesi tämän, sinun on ymmärrettävä, kuinka kieli sopii taustalla olevaan laitteistoon.
Martin Thompson valitsi loistavan sanan blogiinsa Mekaaninen sympatia! Sinun on ymmärrettävä, mitä laitteisto aikoo tehdä, kuinka se tarkalleen tekee sen ja miksi se tekee mitä se ylipäätään tekee. Tätä käyttämällä on melko helppoa alkaa laskea ohjeita ja selvittää, mihin suoritusaika menee. Jos sinulla ei ole asianmukaista koulutusta, etsit vain mustaa kissaa pimeään huoneeseen. Näen ihmisten optimoivan suorituskykyä koko ajan, joilla ei ole aavistustakaan, mitä he tekevät. He kärsivät paljon eivätkä edisty paljoa. Ja kun otan saman koodinpätkän, sujahdan sisään pari pientä hakkeria ja saan viisi- tai kymmenkertaisen nopeuden, ne ovat kuin: no, se ei ole reilua, tiesimme jo, että olet parempi. Hämmästyttävä. Mistä minä puhun... kustannusmallissa on kyse siitä, millaista koodia kirjoitat ja kuinka nopeasti se toimii keskimäärin isossa kuvassa.

Andrew: Ja kuinka voit pitää sellaisen volyymin päässäsi? Onko tämä saavutettu suuremmalla kokemuksella vai? Mistä tällainen kokemus on peräisin?

Cliff: No, en saanut kokemustani helpoimmalla tavalla. Ohjelmoin Assemblyssa silloin, kun ymmärsit jokaisen ohjeen. Kuulostaa typerältä, mutta siitä lähtien Z80-ohjesarja on aina pysynyt päässäni, muistissani. En muista ihmisten nimiä minuutin sisällä puhumisesta, mutta muistan 40 vuotta sitten kirjoitetun koodin. Se on hauskaa, se näyttää syndroomalta"idiootti tiedemies'.

Matalan tason optimointikoulutus

Andrew: Onko helpompaa tapaa päästä sisään?

Cliff: Kyllä ja ei. Kaikki käyttämämme laitteistot eivät ole muuttuneet juurikaan ajan mittaan. Kaikki käyttävät x86:ta Arm-älypuhelimia lukuun ottamatta. Jos et tee jonkinlaista hardcore-upotusta, teet saman asian. Okei, seuraavaksi. Ohjeet eivät myöskään ole muuttuneet vuosisatojen ajan. Sinun täytyy mennä ja kirjoittaa jotain Assemblyyn. Ei paljon, mutta tarpeeksi ymmärtääkseni. Sinä hymyilet, mutta minä puhun täysin vakavasti. Sinun on ymmärrettävä kielen ja laitteiston välinen vastaavuus. Sen jälkeen sinun täytyy mennä kirjoittamaan vähän ja tehdä pieni lelu kääntäjä pienelle lelukielelle. Lelumainen tarkoittaa, että se on valmistettava kohtuullisessa ajassa. Se voi olla erittäin yksinkertainen, mutta sen on luotava ohjeita. Ohjeen luominen auttaa ymmärtämään kustannusmallin siltalle kaikkien kirjoittaman korkean tason koodin ja laitteistossa toimivan konekoodin välillä. Tämä kirjeenvaihto poltetaan aivoihin, kun kääntäjä kirjoitetaan. Jopa yksinkertaisin kääntäjä. Sen jälkeen voit alkaa tarkastella Javaa ja sitä, että sen semanttinen kuilu on paljon syvemmällä, ja sen yli on paljon vaikeampaa rakentaa siltoja. Javalla on paljon vaikeampaa ymmärtää, oliko sillamme hyvä vai huono, mikä saa sen hajoamaan ja mikä ei. Mutta tarvitset jonkinlaisen aloituskohdan, jossa katsot koodia ja ymmärrät: "Joo, tämä getteri tulisi kirjoittaa joka kerta." Ja sitten käy ilmi, että toisinaan näin tapahtuu, paitsi tilanteessa, jossa menetelmästä tulee liian suuri ja JIT alkaa sisällyttää kaiken. Tällaisten paikkojen suorituskyky voidaan ennustaa välittömästi. Yleensä getterit toimivat hyvin, mutta sitten katsot suuria kuumasilmukoita ja huomaat, että siellä leijuu joitain funktiokutsuja, jotka eivät tiedä mitä tekevät. Tämä on ongelma haittojen laajassa käytössä, syy siihen, miksi niitä ei ole sisällytetty, on se, että ei ole selvää, ovatko ne getterit. Jos sinulla on erittäin pieni koodikanta, voit yksinkertaisesti muistaa sen ja sanoa: tämä on getteri ja tämä on asettaja. Suuressa koodikannassa jokainen funktio elää omaa historiaansa, jota ei yleensä tiedä kukaan. Profiloija sanoo, että menetimme 24% ajasta jossain silmukassa ja ymmärtääksemme, mitä tämä silmukka tekee, meidän on tarkasteltava jokaista toimintoa sisällä. Tätä on mahdotonta ymmärtää ilman funktion tutkimista, ja tämä hidastaa ymmärtämisprosessia vakavasti. Siksi en käytä gettereitä ja settereitä, olen saavuttanut uuden tason!
Mistä saa kustannusmallin? No, voit tietysti lukea jotain... Mutta mielestäni paras tapa on toimia. Pienen kääntäjän tekeminen on paras tapa ymmärtää kustannusmalli ja sovittaa se omaan päähän. Pieni kääntäjä, joka sopisi mikroaaltouunin ohjelmointiin, on aloittelijan tehtävä. Tarkoitan, jos sinulla on jo ohjelmointitaitoja, sen pitäisi riittää. Kaikki nämä asiat, kuten jonkinlaisena algebrallisena lausekkeena olevan merkkijonon jäsentäminen, matemaattisten toimintojen ohjeiden poimiminen sieltä oikeassa järjestyksessä, oikeiden arvojen ottaminen rekistereistä - kaikki tämä tehdään kerralla. Ja kun teet sen, se painuu aivoihisi. Luulen, että kaikki tietävät, mitä kääntäjä tekee. Ja tämä antaa käsityksen kustannusmallista.

Käytännön esimerkkejä suorituskyvyn parantamisesta

Andrew: Mihin muuhun sinun tulee kiinnittää huomiota tuottavuuden parantamiseksi?

Cliff: Tietorakenteet. Muuten, kyllä, en ole opettanut näitä luokkia pitkään aikaan... Rakettikoulu. Se oli hauskaa, mutta vaati paljon vaivaa, ja minulla on myös elämä! OK. Joten eräässä suuressa ja mielenkiintoisessa tunnissa, "Mihin suorituskykysi menee", annoin opiskelijoille esimerkin: kaksi ja puoli gigatavua fintech-dataa luettiin CSV-tiedostosta ja sitten heidän piti laskea myytyjen tuotteiden määrä. . Säännöllinen punkkimarkkinoiden data. UDP-paketit muutettu tekstimuotoon 70-luvulta lähtien. Chicago Mercantile Exchange - kaikenlaisia ​​asioita, kuten voita, maissia, soijapapuja, sellaisia ​​asioita. Oli tarpeen laskea nämä tuotteet, tapahtumien määrä, varojen ja tavaroiden keskimääräinen liikkuvuus jne. Se on melko yksinkertaista kaupankäynnin matematiikkaa: etsi tuotekoodi (se on 1-2 merkkiä hash-taulukossa), hanki summa, lisää se johonkin kauppasarjasta, lisää volyymia, lisää arvoa ja pari muuta asiaa. Hyvin yksinkertainen matematiikka. Lelun toteutus oli hyvin suoraviivaista: kaikki on tiedostossa, luen tiedoston ja liikun sen läpi jakaen yksittäiset tietueet Java-merkkijonoiksi, etsin niistä tarvittavat asiat ja lasken ne yhteen yllä kuvatun matematiikan mukaan. Ja toimii pienellä nopeudella.

Tällä lähestymistavalla on selvää, mitä tapahtuu, eikä rinnakkaislaskenta auta, eikö niin? Osoittautuu, että viisinkertainen suorituskyvyn kasvu voidaan saavuttaa yksinkertaisesti valitsemalla oikeat tietorakenteet. Ja tämä yllättää jopa kokeneet ohjelmoijat! Minun tapauksessani temppu oli se, että sinun ei pitäisi tehdä muistin varauksia kuumassa silmukassa. No, tämä ei ole koko totuus, mutta yleisesti - sinun ei pitäisi korostaa "kerran X:ssä", kun X on tarpeeksi suuri. Kun X on kaksi ja puoli gigatavua, sinun ei pitäisi allokoida mitään "kerran per kirjain", "kerran per rivi" tai "kerran per kenttä", mitään sellaista. Tässä aika kuluu. Miten tämä edes toimii? Kuvittele minun soittavani String.split() tai BufferedReader.readLine(). Readline tekee merkkijonon joukosta tavuja, jotka tulivat verkon yli, kerran kullekin riville, jokaiselle sadoille miljoonille riveille. Otan tämän rivin, jäsentelen sen ja heitän pois. Miksi heitän sen pois - no, olen jo käsitellyt sen, siinä kaikki. Joten jokaista näistä 2.7G:stä luettua tavua kohden kirjoitetaan riville kaksi merkkiä, eli jo 5.4G, enkä tarvitse niitä enää mihinkään, joten ne heitetään pois. Jos tarkastellaan muistin kaistanleveyttä, lataamme 2.7G, joka kulkee prosessorin muistin ja muistiväylän kautta, ja sitten lähetetään kaksinkertainen määrä muistissa olevalle linjalle, ja kaikki tämä kuluu, kun jokainen uusi rivi luodaan. Mutta minun on luettava se, laitteisto lukee sen, vaikka kaikki kuluisi myöhemmin. Ja minun on kirjoitettava se muistiin, koska loin rivin ja välimuistit ovat täynnä - välimuisti ei mahdu 2.7 Gt. Joten jokaista lukemaani tavua kohden luen vielä kaksi tavua ja kirjoitan vielä kaksi tavua, ja lopulta niiden suhde on 4:1 - tässä suhteessa hukkaamme muistin kaistanleveyttä. Ja sitten käy ilmi, että jos teen String.split() – Tämä ei ole viimeinen kerta, kun teen tämän, sisällä voi olla vielä 6-7 kenttää. Joten klassinen CSV-koodin lukeminen ja sitten merkkijonojen jäsentäminen johtaa muistin kaistanleveyden hukkaan, joka on noin 14:1 suhteessa siihen, mitä todella haluaisit. Jos heität nämä valinnat pois, saat viisinkertaisen nopeuden.

Eikä se ole niin vaikeaa. Jos katsot koodia oikeasta näkökulmasta, kaikesta tulee melko yksinkertaista, kun huomaat ongelman. Muistin varaamista ei pidä lopettaa kokonaan: ainoa ongelma on, että varaat jotain ja se kuolee välittömästi, ja matkan varrella se polttaa tärkeän resurssin, joka tässä tapauksessa on muistin kaistanleveys. Ja kaikki tämä johtaa tuottavuuden laskuun. x86:lla sinun on yleensä poltettava prosessorijaksoja aktiivisesti, mutta tässä poltit kaiken muistin paljon aikaisemmin. Ratkaisu on vähentää vuodon määrää. 
Toinen osa ongelmaa on, että jos käytät profilointia, kun muistiraita loppuu, juuri kun se tapahtuu, odotat yleensä välimuistin palautumista, koska se on täynnä juuri tuottamaasi roskaa, kaikki nuo rivit. Siksi jokainen lataus tai varastotoiminto hidastuu, koska ne johtavat välimuistin hukkaan - koko välimuisti on hidastunut odottamassa roskien poistumista. Siksi profiloija näyttää vain lämmintä satunnaista kohinaa koko silmukan ajan - koodissa ei ole erillistä kuumaa ohjetta tai paikkaa. Vain melua. Ja jos katsot GC-syklejä, ne ovat kaikki Young Generation ja supernopeita - mikrosekunteja tai millisekunteja maksimissaan. Loppujen lopuksi kaikki tämä muisto kuolee välittömästi. Varaat miljardeja gigatavuja, ja hän leikkaa ne ja leikkaa ne ja leikkaa ne uudelleen. Kaikki tämä tapahtuu hyvin nopeasti. Osoittautuu, että on halpoja GC-syklejä, lämmintä melua koko syklin ajan, mutta haluamme saada 5x nopeuden. Tällä hetkellä jonkin pitäisi sulkeutua päässäsi ja kuulua: "miksi tämä on?!" Muistiliuskan ylivuoto ei näy perinteisessä debuggerissa; sinun on suoritettava laitteiston suorituskyvyn laskurin debuggeri ja katsottava se itse ja suoraan. Mutta tätä ei voida suoraan epäillä näiden kolmen oireen perusteella. Kolmas oire on, kun katsot mitä korostat, kysy profiloijalta, ja hän vastaa: "Teit miljardi riviä, mutta GC toimi ilmaiseksi." Heti kun tämä tapahtuu, huomaat, että olet luonut liian monta esinettä ja polttanut koko muistikaistan. On olemassa tapa selvittää tämä, mutta se ei ole itsestään selvää. 

Ongelma on tietorakenteessa: kaiken tapahtuvan taustalla oleva paljas rakenne, se on liian suuri, se on 2.7 Gt levyllä, joten tämän kopion tekeminen on erittäin epätoivottavaa - haluat ladata sen heti verkon tavupuskurista rekistereihin, jotta riville ei tarvitse lukea ja kirjoittaa viisi kertaa edestakaisin. Valitettavasti Java ei anna sinulle tällaista kirjastoa osana JDK:ta oletuksena. Mutta tämä on triviaalia, eikö? Pohjimmiltaan nämä ovat 5-10 koodiriviä, joita käytetään oman puskuroidun merkkijonolataimen toteuttamiseen, joka toistaa merkkijonoluokan käyttäytymisen samalla kun se on kääre taustalla olevan tavupuskurin ympärillä. Tuloksena käy ilmi, että työskentelet melkein kuin merkkijonojen kanssa, mutta itse asiassa puskuriin osoittavat osoittimet liikkuvat siellä, eikä raakatavuja kopioida mihinkään, ja siten samoja puskureita käytetään uudelleen ja uudelleen, ja käyttöjärjestelmä ottaa mielellään itsellesi ne asiat, joihin se on suunniteltu, kuten näiden tavupuskurien piilotettu kaksoispuskurointi, etkä enää hiero tarpeettoman datan loputonta virtaa. Ymmärrätkö muuten, että kun työskentelet GC:n kanssa, on taattu, että jokainen muistivaraus ei näy prosessorille viimeisen GC-jakson jälkeen? Siksi kaikki tämä ei voi olla välimuistissa, ja silloin tapahtuu 100% taattu ohitus. Kun työskentelet osoittimella, x86:lla rekisterin vähentäminen muistista kestää 1-2 kellojaksoa ja heti kun tämä tapahtuu, maksat, maksat, maksat, koska muisti on päällä yhdeksän välimuistia – ja tämä on muistin varauksen hinta. Todellinen arvo.

Toisin sanoen tietorakenteet ovat vaikeinta muuttaa. Ja kun huomaat, että olet valinnut väärän tietorakenteen, joka tuhoaa suorituskyvyn myöhemmin, on yleensä paljon työtä tehtävänä, mutta jos et, asiat pahenevat. Ensinnäkin sinun on mietittävä tietorakenteita, tämä on tärkeää. Suurin kustannukset ovat tässä rasvatietorakenteissa, joita aletaan käyttää tyyliin "kopioin tietorakenteen X tietorakenteeseen Y, koska pidän Y:n muodosta enemmän." Mutta kopiointitoiminto (joka vaikuttaa halvalta) itse asiassa tuhlaa muistin kaistanleveyttä ja sinne kaikki hukkaan kulunut suoritusaika haudataan. Jos minulla on jättimäinen JSON-merkkijono ja haluan muuttaa sen POJO:iden strukturoiduksi DOM-puuksi tai vastaavaksi, tämän merkkijonon jäsentäminen ja POJOn rakentaminen ja POJOn käyttäminen myöhemmin uudelleen aiheuttaa tarpeettomia kustannuksia - se on ei halpa. Paitsi jos juokset POJOjen ympärillä paljon useammin kuin juokset merkkijonon ympärillä. Voit sen sijaan yrittää purkaa merkkijonon salauksen ja poimia sieltä vain sen, mitä tarvitset, muuttamatta sitä POJO:ksi. Jos kaikki tämä tapahtuu polulla, jolta vaaditaan maksimaalista suorituskykyä, ei POJOja sinulle, sinun täytyy jotenkin kaivaa linjaan suoraan.

Miksi luoda oma ohjelmointikieli

Andrew: Sanoit, että ymmärtääksesi kustannusmallin sinun on kirjoitettava oma pieni kieli...

Cliff: Ei kieli, vaan kääntäjä. Kieli ja kääntäjä ovat kaksi eri asiaa. Tärkein ero on päässäsi. 

Andrew: Muuten, tietääkseni kokeilet omien kielten luomista. Minkä vuoksi?

Cliff: Koska minä voin! Olen puoliksi eläkkeellä, joten tämä on harrastukseni. Olen käyttänyt muiden kieliä koko ikäni. Työskentelin myös paljon koodaustyylini parissa. Ja myös siksi, että näen ongelmia muissa kielissä. Näen, että on olemassa parempiakin tapoja tehdä tuttuja asioita. Ja käyttäisin niitä. Olen vain kyllästynyt näkemään ongelmia itsessäni, Javassa, Pythonissa, millä tahansa muulla kielellä. Kirjoitan nyt React Nativeen, JavaScriptiin ja Elmiin harrastuksena, jossa ei ole kyse eläkkeelle jäämisestä, vaan aktiivisesta työstä. Kirjoitan myös Pythonilla ja todennäköisesti jatkan Java-taustaohjelmien koneoppimisen parissa. On olemassa monia suosittuja kieliä ja niillä kaikilla on mielenkiintoisia ominaisuuksia. Jokainen on hyvä omalla tavallaan ja voit yrittää yhdistää kaikki nämä ominaisuudet. Joten, tutkin asioita, jotka kiinnostavat minua, kielen käyttäytymistä, yritän keksiä järkevää semantiikkaa. Ja toistaiseksi olen onnistunut! Tällä hetkellä kamppailen muistisemantiikan kanssa, koska haluan sen olevan kuten C:ssä ja Javassa sekä vahvan muistimallin ja muistisemantiikan latauksille ja varastoille. Samalla on automaattinen tyyppipäätelmä, kuten Haskellissa. Tässä yritän sekoittaa Haskell-tyyppistä päättelyä muistityöhön sekä C:ssä että Javassa. Tätä olen tehnyt esimerkiksi viimeiset 2-3 kuukautta.

Andrew: Jos rakennat kielen, joka ottaa parempia puolia muista kielistä, luuletko, että joku tekee päinvastoin: ottaa ideasi ja käyttää niitä?

Cliff: Juuri näin uudet kielet ilmestyvät! Miksi Java on samanlainen kuin C? Koska C:llä oli hyvä syntaksi, jonka kaikki ymmärsivät ja Java inspiroitui tästä syntaksista, lisäten tyyppiturvallisuutta, taulukkorajojen tarkistusta, GC:tä, ja he myös paransivat joitain asioita C:stä. He lisäsivät omansa. Mutta he inspiroituivat aika paljon, eikö niin? Kaikki seisovat ennen sinua tulleiden jättiläisten harteilla - näin edistytään.

Andrew: Ymmärtääkseni kielesi on muistiturvallinen. Oletko ajatellut toteuttaa jotain, kuten lainaustarkistusta Rustilta? Oletko katsonut häntä, mitä mieltä olet hänestä?

Cliff: No, olen kirjoittanut C:tä iät ja ajat, kaiken tämän mallocin ja ilmaisen kanssa, ja hallitsen manuaalisesti koko eliniän. Tiedäthän, että 90-95 %:lla manuaalisesti ohjatusta käyttöiästä on sama rakenne. Ja se on erittäin, erittäin tuskallista tehdä se käsin. Haluaisin kääntäjän vain kertovan, mitä siellä tapahtuu ja mitä olet saavuttanut toiminnallasi. Joidenkin asioiden osalta lainatarkistus tekee tämän heti. Ja sen pitäisi automaattisesti näyttää tietoa, ymmärtää kaikki, eikä edes rasittaa minua tämän ymmärryksen esittämisellä. Sen on tehtävä ainakin paikallinen pakoanalyysi, ja vain jos se epäonnistuu, sen on lisättävä tyyppihuomautuksia, jotka kuvaavat elinikää - ja tällainen järjestelmä on paljon monimutkaisempi kuin lainaustarkistus tai jopa mikä tahansa olemassa oleva muistitarkistus. Valinta "kaikki on hyvin" ja "en ymmärrä mitään" välillä - ei, täytyy olla jotain parempaa. 
Joten ihmisenä, joka on kirjoittanut paljon koodia C-kielellä, uskon, että automaattisen elinikäisen ohjauksen tuki on tärkeintä. Olen myös kyllästynyt siihen, kuinka paljon Java käyttää muistia, ja suurin valitus on GC. Kun varaat muistia Javassa, et saa takaisin muistia, joka oli paikallinen viimeisellä GC-jaksolla. Näin ei ole kielissä, joissa on tarkempi muistinhallinta. Jos soitat mallocille, saat välittömästi muistin, jota yleensä käytettiin. Yleensä teet joitain väliaikaisia ​​asioita muistilla ja palautat sen välittömästi takaisin. Ja se palaa välittömästi malloc-pooliin, ja seuraava malloc-sykli vetää sen jälleen pois. Siksi todellinen muistin käyttö vähenee tiettynä ajankohtana elävien esineiden joukkoon plus vuodot. Ja jos kaikki ei vuoda täysin sopimattomalla tavalla, suurin osa muistista päätyy välimuistiin ja prosessoriin, ja se toimii nopeasti. Mutta vaatii paljon manuaalista muistinhallintaa mallocilla ja ilmaisilla kutsuilla oikeassa järjestyksessä, oikeassa paikassa. Rust pystyy käsittelemään tämän kunnolla yksinään ja antaa monissa tapauksissa jopa paremman suorituskyvyn, koska muistin kulutus on rajattu vain nykyiseen laskelmaan - sen sijaan, että odotettaisiin seuraavaa GC-sykliä muistin vapauttamiseksi. Tuloksena saimme erittäin mielenkiintoisen tavan parantaa suorituskykyä. Ja melko tehokas - tarkoitan, tein sellaisia ​​​​asioita käsitellessään tietoja fintechille, ja tämä antoi minulle mahdollisuuden saada noin viisinkertainen nopeus. Se on melko suuri lisä, varsinkin maailmassa, jossa prosessorit eivät nouse ja odotamme edelleen parannuksia.

Performance Engineerin ura

Andrew: Haluaisin myös kysyä ammateista yleensä. Nousit tunnetuksi JIT-työlläsi HotSpotissa ja muutit sitten Azuliin, joka on myös JVM-yritys. Mutta työskentelimme jo enemmän laitteiston kuin ohjelmiston parissa. Ja sitten he yhtäkkiä siirtyivät Big Dataan ja koneoppimiseen ja sitten petosten havaitsemiseen. Kuinka tämä tapahtui? Nämä ovat hyvin erilaisia ​​kehityskohteita.

Cliff: Olen ohjelmoinut melko pitkään ja olen onnistunut käymään paljon erilaisia ​​tunteja. Ja kun ihmiset sanovat: "Oi, sinä olet se, joka teki JIT:n Javalle!", se on aina hauskaa. Mutta ennen sitä työskentelin PostScriptin kloonin parissa – kielellä, jota Apple käytti kerran lasertulostimissaan. Ja ennen sitä toteutin Forth-kielen. Mielestäni yhteinen teema minulle on työkalujen kehittäminen. Olen koko ikäni tehnyt työkaluja, joilla muut ihmiset kirjoittavat hienoja ohjelmiaan. Mutta olin myös mukana kehittämässä käyttöjärjestelmiä, ohjaimia, ydintason virheenkorjausohjelmia, käyttöjärjestelmän kehittämiseen tarkoitettuja kieliä, jotka alkoivat triviaalia, mutta ajan myötä muuttuivat yhä monimutkaisemmiksi. Mutta pääaihe on edelleen työkalujen kehittäminen. Suuri osa elämästäni kului Azulin ja Sunin välillä, ja se koski Javaa. Mutta kun aloin Big Datan ja koneoppimisen parissa, laitoin hienon hattuni takaisin päähäni ja sanoin: "Voi, nyt meillä on ei-triviaali ongelma, ja siellä tapahtuu paljon mielenkiintoisia asioita ja ihmiset tekevät asioita." Tämä on loistava kehityspolku.

Kyllä, rakastan todella hajautettua tietojenkäsittelyä. Ensimmäinen työpaikkani oli C:n opiskelijana mainosprojektissa. Tämä oli hajautettu laskenta Zilog Z80 -siruille, jotka keräsivät dataa analogista OCR:ää varten ja jotka tuotettiin todellisella analogisella analysaattorilla. Se oli siisti ja täysin hullu aihe. Mutta oli ongelmia, jotain osaa ei tunnistettu oikein, joten piti ottaa kuva ja näyttää se henkilölle, joka osasi jo lukea silmillään ja raportoida, mitä se sanoi, ja siksi oli töitä, joissa oli dataa, ja nämä työt oli oma kieli. Oli taustajärjestelmä, joka käsitteli kaiken tämän - Z80:t toimivat rinnakkain vt100-päätteiden kanssa - yksi per henkilö, ja Z80:ssä oli rinnakkaisohjelmointimalli. Yhteinen muisti, jota jakavat kaikki tähtikokoonpanon Z80:t; Myös taustalevy oli jaettu, ja puolet RAM-muistista jaettiin verkon sisällä, ja toinen puoli oli yksityistä tai meni johonkin muuhun. Mielellään monimutkainen rinnakkainen hajautettu järjestelmä jaetulla... puolijaetulla muistilla. Milloin tämä oli... En edes muista, jossain 80-luvun puolivälissä. Aika kauan sitten. 
Kyllä, oletetaan, että 30 vuotta on melko pitkä aika. Hajautettuun laskemiseen liittyvät ongelmat ovat olleet olemassa jo pitkään, ihmiset ovat pitkään olleet sodassa Beowulf-klusterit. Sellaiset klusterit näyttävät... Esimerkiksi: on Ethernet ja nopea x86 on kytketty tähän Ethernetiin, ja nyt haluat saada väärennetyn jaetun muistin, koska kukaan ei silloin pystynyt tekemään hajautettua laskennallista koodausta, se oli liian vaikeaa ja siksi siellä oli väärennetty jaettu muisti suojamuistisivuilla x86:ssa, ja jos kirjoitit tälle sivulle, kerroimme muille prosessoreille, että jos he käyttävät samaa jaettua muistia, se on ladattava sinulta, ja siten jotain tukiprotokollaa. välimuistin koherenssi ja ohjelmisto tätä varten. Mielenkiintoinen konsepti. Todellinen ongelma oli tietysti jotain muuta. Kaikki tämä toimi, mutta sait nopeasti suorituskykyongelmia, koska kukaan ei ymmärtänyt suorituskykymalleja tarpeeksi hyvällä tasolla - mitä muistin käyttökuvioita siellä oli, miten varmistua siitä, että solmut eivät pingaa toisiaan loputtomasti jne.

H2O:ssa keksin, että kehittäjät itse ovat vastuussa sen määrittämisestä, missä rinnakkaisuus on piilotettu ja missä ei. Keksin koodausmallin, joka teki tehokkaan koodin kirjoittamisesta helppoa ja yksinkertaista. Mutta hitaasti juoksevan koodin kirjoittaminen on vaikeaa, se näyttää huonolta. Sinun on yritettävä vakavasti kirjoittaa hidasta koodia, sinun on käytettävä epätyypillisiä menetelmiä. Jarrukoodi näkyy ensi silmäyksellä. Tämän seurauksena yleensä kirjoitat koodia, joka toimii nopeasti, mutta sinun on selvitettävä, mitä tehdä jaetun muistin tapauksessa. Kaikki tämä on sidottu suuriin taulukoihin ja käyttäytyminen siellä on samanlaista kuin haihtumattomissa suurissa taulukoissa rinnakkaisessa Javassa. Tarkoitan, kuvittele, että kaksi säiettä kirjoittaa rinnakkaiseen taulukkoon, joista toinen voittaa ja toinen vastaavasti häviää, etkä tiedä kumpi on kumpi. Jos ne eivät ole epävakaita, tilaus voi olla mitä haluat - ja tämä toimii todella hyvin. Ihmiset todella välittävät toimintajärjestyksestä, he laittavat volatilit oikeisiin paikkoihin ja odottavat muistiin liittyviä suorituskykyongelmia oikeissa paikoissa. Muuten he yksinkertaisesti kirjoittaisivat koodia silmukoiden muodossa 1:stä N:ään, missä N on joitain biljoonia, siinä toivossa, että kaikki monimutkaiset tapaukset muuttuvat automaattisesti rinnakkaiksi - eikä se toimi siellä. Mutta H2O:ssa tämä ei ole Java eikä Scala; voit pitää sitä "Java miinus miinus" jos haluat. Tämä on erittäin selkeä ohjelmointityyli ja muistuttaa yksinkertaisen C- tai Java-koodin kirjoittamista silmukoilla ja taulukoilla. Mutta samalla muistia voidaan käsitellä teratavuina. Käytän edelleen H2O:ta. Käytän sitä silloin tällöin erilaisissa projekteissa - ja se on silti nopein, kymmeniä kertoja nopeampi kuin kilpailijansa. Jos teet Big Dataa saraketiedoilla, H2O:ta on erittäin vaikea voittaa.

Tekniset haasteet

Andrew: Mikä on ollut suurin haasteesi koko urasi aikana?

Cliff: Keskustelemmeko ongelman teknisestä vai ei-teknisestä osasta? Sanoisin, että suurimmat haasteet eivät ole teknisiä. 
Mitä tulee teknisiin haasteisiin. Minä yksinkertaisesti voitin heidät. En edes tiedä, mikä oli suurin, mutta siellä oli joitain melko mielenkiintoisia, jotka veivät melkoisen aikaa, henkistä kamppailua. Kun menin Suniin, olin varma, että teen nopean kääntäjän, ja joukko senioreita vastasi, että en koskaan onnistuisi. Mutta minä seurasin tätä polkua, kirjoitin kääntäjän rekisterialokaattoriin, ja se oli melko nopea. Se oli yhtä nopea kuin nykyaikainen C1, mutta allokaattori oli tuolloin paljon hitaampi, ja jälkikäteen ajatellen se oli suuri tietorakenneongelma. Tarvitsin sitä graafisen rekisteriallokaattorin kirjoittamiseen, enkä ymmärtänyt koodin ilmaisukyvyn ja nopeuden välistä dilemmaa, joka oli tuolloin olemassa ja oli erittäin tärkeä. Kävi ilmi, että tietorakenne ylittää yleensä välimuistin koon tuolloisilla x86:illa, ja siksi, jos oletin alunperin, että rekisterialokaattori hoitaa 5-10 prosenttia koko jitter-ajasta, niin todellisuudessa se osoittautui 50 prosenttia.

Ajan myötä kääntäjästä tuli puhtaampi ja tehokkaampi, se lakkasi luomasta kauheaa koodia useammissa tapauksissa ja suorituskyky alkoi yhä enemmän muistuttaa C-kääntäjän tuottamaa. Ellei tietysti kirjoita paskaa, jota edes C ei nopeuta. . Jos kirjoitat koodin kuten C, saat C:n kaltaista suorituskykyä useammissa tapauksissa. Ja mitä pidemmälle menit, sitä useammin sait koodia, joka asymptoottisesti osui yhteen tason C kanssa, rekisterialokaattori alkoi näyttää joltain täydelliseltä... riippumatta siitä, toimiiko koodisi nopeasti vai hitaasti. Jatkoin allokaattorin työstämistä, jotta se tekisi parempia valintoja. Hänestä tuli hitaampi ja hitaampi, mutta hän suoritti yhä paremman suorituskyvyn tapauksissa, joissa kukaan muu ei kestänyt. Voisin sukeltaa rekisterialokaattoriin, haudata kuukauden työn sinne, ja yhtäkkiä koko koodi alkoi suorittaa 5% nopeammin. Tätä tapahtui kerta toisensa jälkeen ja rekisterialokaattorista tuli jonkinlainen taideteos - kaikki rakastivat sitä tai vihasivat sitä, ja akatemiasta tuli kysymyksiä aiheesta "miksi kaikki tehdään näin", miksi ei linjaskannaus, ja mitä eroa sillä on. Vastaus on edelleen sama: graafin värjäykseen perustuva allokaattori ja erittäin huolellinen puskurikoodin käsittely on yhtä suuri kuin voiton ase, paras yhdistelmä, jota kukaan ei voi voittaa. Ja tämä on melko epäselvä asia. Kaikki muu, mitä kokoaja siellä tekee, on melko hyvin tutkittua asiaa, vaikka ne on myös tuotu taiteen tasolle. Tein aina asioita, joiden piti tehdä kääntäjästä taideteos. Mutta mikään näistä ei ollut mitään poikkeuksellista - paitsi rekisterin jakaja. Temppu on olla varovainen kaataa kuormituksen alaisena ja jos näin tapahtuu (voin selittää tarkemmin, jos kiinnostaa), tämä tarkoittaa, että voit upottaa aggressiivisemmin ilman riskiä, ​​että putoat esitysaikataulun mutkista. Noihin aikoihin oli joukko täysimittaisia ​​kääntäjiä, jotka oli ripustettu koruihin ja pilleihin ja joissa oli rekisterialokaattorit, mutta kukaan muu ei voinut tehdä sitä.

Ongelmana on, että jos lisäät menetelmiä, joihin rivitys kohdistuu, lisätään ja lisätään rivitysaluetta, käytettyjen arvojen joukko ylittää välittömästi rekisterien määrän, ja sinun on leikattava niitä. Kriittinen taso tulee yleensä silloin, kun allokaattori luovuttaa, ja yksi hyvä ehdokas vuotolle on toisen arvoinen, myyt joitain yleisesti hurjia asioita. Sisällön arvo tässä on, että menetät osan yleiskustannuksista, puhelun ja tallennuksen yleiskulut, näet arvot sisällä ja voit optimoida niitä edelleen. Sisäänpanon hinta on, että muodostuu suuri määrä live-arvoja, ja jos rekisterialokaattorisi palaa tarpeettoman paljon, häviät välittömästi. Siksi useimmilla allokaattoreilla on ongelma: kun vuoraus ylittää tietyn rajan, kaikkea maailmassa alkaa leikata ja tuottavuus voidaan huuhdella WC:stä. Kääntäjän toteuttajat lisäävät heuristiikkaa: esimerkiksi lopettaa rivityksen, aloittaen jostain riittävän suuresta koosta, koska allokaatiot pilaavat kaiken. Näin suorituskaavioon muodostuu mutka - sinä inline, inline, suorituskyky kasvaa hitaasti - ja sitten buumi! – se putoaa alas kuin nopea tunkki, koska vuorasit liikaa. Näin kaikki toimi ennen Javan tuloa. Java vaatii paljon enemmän inliningia, joten minun piti tehdä allokaattoristani paljon aggressiivisempi, jotta se tasoittuisi, ei kaatuisi, ja jos linjaa liikaa, se alkaa roiskua, mutta sitten tulee silti "ei enää vuoda" -hetki. Tämä on mielenkiintoinen havainto, ja se tuli minulle aivan tyhjästä, ei ilmeinen, mutta se kannatti hyvin. Otin käyttöön aggressiivisen inliningin ja se vei minut paikkoihin, joissa Java- ja C-suorituskyky toimivat rinnakkain. Ne ovat todella lähellä - voin kirjoittaa Java-koodia, joka on huomattavasti nopeampi kuin C-koodi ja muut vastaavat, mutta keskimäärin ne ovat asioiden suuressa kuvassa suunnilleen vertailukelpoisia. Luulen, että osa tästä ansiosta on rekisterialokaattori, jonka avulla voin kirjoittaa mahdollisimman typerästi. Kirjoitan vain kaiken, mitä näen. Tässä on kysymys, toimiiko allokaattori hyvin, onko tuloksena älykkäästi toimiva koodi. Tämä oli suuri haaste: ymmärtää tämä kaikki ja saada se toimimaan.

Hieman rekisterin allokoinnista ja moniytimistä

Vladimir: Rekisterin allokoinnin kaltaiset ongelmat näyttävät olevan jonkinlainen ikuinen, loputon aihe. Mietin, onko koskaan ollut idea, joka vaikutti lupaavalta ja sitten epäonnistui käytännössä?

Cliff: Varmasti! Rekisterin allokointi on alue, jolla yrität löytää heuristiikkaa NP-täydellisen ongelman ratkaisemiseksi. Etkä koskaan voi saavuttaa täydellistä ratkaisua, eikö niin? Tämä on yksinkertaisesti mahdotonta. Katso, Ahead of Time -kokoelma - se toimii myös huonosti. Keskustelu täällä on keskimääräisistä tapauksista. Tietoja tyypillisestä suorituskyvystä, jotta voit mennä mittaamaan jotain, joka on mielestäsi hyvä tyypillinen suorituskyky - työskentelethän sen parantamiseksi! Rekisteröinnin jakaminen on suorituskykyyn liittyvä aihe. Kun sinulla on ensimmäinen prototyyppi, se toimii ja maalaa tarvittavan, suoritustyö alkaa. Pitää opetella mittaamaan hyvin. Miksi se on tärkeää? Jos sinulla on selkeät tiedot, voit tarkastella eri alueita ja nähdä: kyllä, se auttoi täällä, mutta siellä kaikki meni rikki! Hyviä ideoita tulee, lisäät uutta heuristiikkaa ja yhtäkkiä kaikki alkaa toimia hieman paremmin keskimäärin. Tai sitten se ei käynnisty. Minulla oli joukko tapauksia, joissa taistelimme viiden prosentin suorituskyvystä, joka erotti kehityksemme edellisestä jakajasta. Ja joka kerta se näyttää tältä: jossain voitat, jossain häviät. Jos sinulla on hyvät suorituskyvyn analysointityökalut, voit löytää häviävät ideat ja ymmärtää, miksi ne epäonnistuvat. Ehkä kannattaa jättää kaikki ennalleen, tai ehkä ottaa vakavampi lähestymistapa hienosäätöön tai mennä ulos ja korjata jotain muuta. Se on koko joukko asioita! Tein tämän hienon hakkeroinnin, mutta tarvitsen myös tämän, ja tämän ja tämän - ja niiden kokonaisyhdistelmä antaa joitain parannuksia. Ja yksinäiset voivat epäonnistua. Tämä on NP-täydellisten ongelmien suoritustyön luonne.

Vladimir: Tulee tunne, että esim. allokaattorien maalaus on ongelma, joka on jo ratkaistu. No, se on sinulle päätetty, sanomasi perusteella, joten onko se sitten sen arvoista...

Cliff: Sitä ei sellaisenaan ratkaista. Sinun on muutettava se "ratkaistuksi". On vaikeita ongelmia ja ne on ratkaistava. Kun tämä on tehty, on aika kehittää tuottavuutta. Sinun on lähestyttävä tätä työtä sen mukaisesti - suorita vertailuarvoja, kerää mittareita, selitä tilanteita, joissa vanha hakkerointisi alkoi toimia uudelleen, kun palasit edelliseen versioon (tai päinvastoin, pysähtyi). Ja älä luovuta ennen kuin saavutat jotain. Kuten jo sanoin, jos on hienoja ideoita, jotka eivät toimineet, mutta idearekisterien jakamisen alalla se on suunnilleen loputon. Voit esimerkiksi lukea tieteellisiä julkaisuja. Vaikka nyt tämä alue on alkanut liikkua paljon hitaammin ja on tullut selkeämmäksi kuin nuoruudessaan. Tällä alalla työskentelee kuitenkin lukemattomia ihmisiä ja kaikki heidän ideansa ovat kokeilemisen arvoisia, kaikki odottavat siivillä. Ja et voi sanoa, kuinka hyviä ne ovat, ellet kokeile niitä. Kuinka hyvin ne integroituvat kaikkeen muuhun allokaattorissasi, koska allokaattori tekee paljon asioita, ja jotkin tietyn allokaattorisi ideat eivät toimi, mutta toisessa allokaattorissa ne toimivat helposti. Pääasiallinen tapa voittaa allokaattorille on vetää hitaat tavarat pääpolun ulkopuolelle ja pakottaa se halkeamaan hitaan polkujen rajoja pitkin. Joten jos haluat käyttää GC:tä, valitse hidas polku, deoptimoi, tee poikkeus, kaikkea muuta - tiedät, että nämä asiat ovat suhteellisen harvinaisia. Ja ne ovat todella harvinaisia, tarkistin. Teet ylimääräistä työtä ja se poistaa monia rajoituksia näiltä hitailta poluilta, mutta sillä ei ole väliä, koska ne ovat hitaita ja harvoin kuljettuja. Esimerkiksi nollaosoitin - sitä ei koskaan tapahdu, eikö? Sinulla on oltava useita polkuja eri asioille, mutta ne eivät saa häiritä pääpolkua. 

Vladimir: Mitä mieltä olet moniytimistä, kun ytimiä on tuhansia kerralla? Onko tämä hyödyllinen asia?

Cliff: GPU:n menestys osoittaa, että se on varsin hyödyllinen!

Vladimir: He ovat melko erikoistuneita. Entä yleiskäyttöiset prosessorit?

Cliff: No, se oli Azulin liiketoimintamalli. Vastaus tuli takaisin aikakauteen, jolloin ihmiset todella rakastivat ennustettavaa suorituskykyä. Rinnakkaiskoodin kirjoittaminen oli silloin vaikeaa. H2O-koodausmalli on erittäin skaalautuva, mutta se ei ole yleiskäyttöinen malli. Ehkä hieman yleisempi kuin GPU:ta käytettäessä. Puhutaanko tällaisen asian kehittämisen vai käytön monimutkaisuudesta? Esimerkiksi Azul opetti minulle mielenkiintoisen oppitunnin, melko ei-ilmeisen: pienet välimuistit ovat normaaleja. 

Elämän suurin haaste

Vladimir: Entä ei-tekniset haasteet?

Cliff: Suurin haaste oli olla... ystävällinen ja mukava ihmisille. Ja sen seurauksena jouduin jatkuvasti erittäin konfliktitilanteisiin. Sellaisia, joissa tiesin asioiden menevän pieleen, mutta en tiennyt, kuinka edetä näiden ongelmien kanssa, enkä pystynyt käsittelemään niitä. Tällä tavalla syntyi monia pitkäaikaisia, vuosikymmeniä kestäviä ongelmia. Se, että Javassa on C1- ja C2-kääntäjät, on suora seuraus tästä. Se, että Javalla ei ollut monitasoista käännöstä kymmeneen vuoteen peräkkäin, on myös suora seuraus. On selvää, että tarvitsimme sellaisen järjestelmän, mutta ei ole selvää, miksi sitä ei ollut olemassa. Minulla oli ongelmia yhden insinöörin tai insinööriryhmän kanssa. Kerran, kun aloin työskennellä Sunilla, olin... Okei, ei vain silloin, minulla on yleensä aina oma mielipiteeni kaikesta. Ja ajattelin, että se oli totta, että voit ottaa tämän totuutesi ja kertoa sen suoraan. Varsinkin kun olin järkyttävän oikeassa suurimman osan ajasta. Ja jos et pidä tästä lähestymistavasta... varsinkin jos olet ilmeisen väärässä ja teet hölynpölyä... Yleensä harvat ihmiset voivat sietää tällaista viestintämuotoa. Vaikka jotkut voisivat, kuten minä. Olen rakentanut koko elämäni meritokraattisille periaatteille. Jos näytät minulle jotain väärin, käännyn heti ympäri ja sanon: sanoit hölynpölyä. Samalla tietysti pyydän anteeksi ja kaikkea muuta, panen merkille mahdolliset ansiot ja teen muut oikeat toimet. Toisaalta olen järkyttävän oikeassa järkyttävän suuren prosenttiosuuden suhteen kokonaisajasta. Ja se ei toimi kovin hyvin ihmissuhteissa. En yritä olla kiltti, mutta esitän kysymyksen suoraan. "Tämä ei koskaan toimi, koska yksi, kaksi ja kolme." Ja he sanoivat: "Voi!" Oli muita seurauksia, jotka oli luultavasti parempi jättää huomiotta: esimerkiksi ne, jotka johtivat avioeroon vaimostani ja kymmenen vuoden masennukseen sen jälkeen.

Haaste on kamppailua ihmisten kanssa, heidän käsityksensä kanssa siitä, mitä voit tai ei voi tehdä, mikä on tärkeää ja mikä ei. Koodaustyyliin liittyi monia haasteita. Kirjoitan edelleen paljon koodia, ja siihen aikaan minun piti jopa hidastaa vauhtia, koska tein liian monia rinnakkaisia ​​tehtäviä ja tein ne huonosti sen sijaan, että olisin keskittynyt yhteen. Kun katson taaksepäin, kirjoitin puolet Java JIT -komennon koodista, C2-komennon. Seuraavaksi nopein kooderi kirjoitti puolet hitaammin, seuraava puoli hitaammin, ja se oli eksponentiaalinen lasku. Seitsemäs henkilö tässä rivissä oli hyvin, hyvin hidas - niin tapahtuu aina! Kosketin paljon koodia. Katsoin kuka kirjoitti mitäkin, poikkeuksetta tuijotin heidän koodiaan, tarkastelin niitä jokaista ja jatkoin silti enemmän itse kirjoittamista kuin kukaan heistä. Tämä lähestymistapa ei toimi kovin hyvin ihmisten kanssa. Jotkut ihmiset eivät pidä tästä. Ja kun he eivät pysty käsittelemään sitä, alkavat kaikenlaiset valitukset. Minua esimerkiksi kerran käskettiin lopettamaan koodaus, koska kirjoitin liikaa koodia ja se vaaransi tiimin, ja kaikki kuulosti minusta vitsiltä: jätkä, jos muu tiimi katoaa ja jatkan koodin kirjoittamista, sinä Häviän vain puolet joukkueista. Toisaalta, jos jatkan koodin kirjoittamista ja menetät puolet joukkueesta, se kuulostaa erittäin huonolta johtamiselta. En koskaan oikeastaan ​​ajatellut sitä, en koskaan puhunut siitä, mutta se oli silti jossain päässäni. Ajatus pyöri mielessäni: "Voitko te kaikki leikkiä minulle?" Suurin ongelma oli siis minä ja suhteeni ihmisiin. Nyt ymmärrän itseäni paljon paremmin, olin pitkään ohjelmoijien tiimipäällikkönä ja nyt sanon suoraan ihmisille: tiedäthän, minä olen se, joka olen, ja sinun tulee käsitellä minua - onko ok, jos seison tässä? Ja kun he alkoivat käsitellä sitä, kaikki toimi. Itse asiassa en ole huono enkä hyvä, minulla ei ole huonoja aikeita tai itsekkäitä pyrkimyksiä, se on vain olemukseni, ja minun on elettävä sen kanssa jotenkin.

Andrew: Aivan äskettäin kaikki alkoivat puhua introverttien itsetietoisuudesta ja pehmeistä taidoista yleensä. Mitä voit sanoa tästä?

Cliff: Kyllä, tämä oli oivallus ja opetus, jonka sain avioerostani vaimostani. Avioerosta opin ymmärtämään itseäni. Näin aloin ymmärtämään muita ihmisiä. Ymmärrä, kuinka tämä vuorovaikutus toimii. Tämä johti löytöihin yksi toisensa jälkeen. Oli tietoisuus siitä, kuka olen ja mitä edustan. Mitä teen: joko olen huolissani tehtävästä tai välttelen konflikteja tai jotain muuta - ja tämä itsetietoisuuden taso auttaa todella pitämään itseni hallinnassa. Tämän jälkeen kaikki on paljon helpompaa. Yksi asia, jonka huomasin paitsi itsessäni, myös muissa ohjelmoijaissa, on kyvyttömyys ilmaista ajatuksia, kun olet emotionaalisen stressin tilassa. Esimerkiksi istut siellä koodaamassa, flow-tilassa, ja sitten he juoksevat luoksesi ja alkavat huutaa hysteerisesti, että jotain on rikki ja nyt sinua vastaan ​​ryhdytään äärimmäisiin toimenpiteisiin. Etkä voi sanoa sanaakaan, koska olet emotionaalisessa stressitilassa. Hankitun tiedon avulla voit valmistautua tähän hetkeen, selviytyä siitä ja siirtyä retriittisuunnitelmaan, jonka jälkeen voit tehdä jotain. Joten kyllä, kun alat ymmärtää, kuinka se kaikki toimii, se on valtava elämää muuttava tapahtuma. 
Itse en löytänyt oikeita sanoja, mutta muistin toimintosarjan. Asia on siinä, että tämä reaktio on yhtä paljon fyysistä kuin sanallista, ja tarvitset tilaa. Sellaista tilaa zenin merkityksessä. Juuri tämä on selitettävä, ja astu sitten välittömästi sivuun - puhtaasti fyysisesti. Kun olen suullisesti hiljaa, pystyn käsittelemään tilanteen emotionaalisesti. Kun adrenaliini saavuttaa aivosi, kytkee sinut taistelu- tai lentotilaan, et voi enää sanoa mitään, ei - nyt olet idiootti, ruoskiva insinööri, joka ei pysty reagoimaan kunnollisesti tai edes pysäyttämään hyökkäystä, ja hyökkääjä on vapaa hyökätä uudestaan ​​ja uudestaan. Sinun on ensin tultava uudelleen omaksesi, saatava hallinta takaisin, poistuttava "taistele tai pakene" -tilasta.

Ja tätä varten tarvitsemme sanallista tilaa. Vain vapaata tilaa. Jos sanot yhtään mitään, voit sanoa juuri sen ja sitten mennä ja todella löytää "tilaa" itsellesi: mene kävelylle puistoon, lukitse itsesi suihkuun - sillä ei ole väliä. Tärkeintä on tilapäisesti irrottaa tilanne. Heti kun sammutat virran vähintään muutamaksi sekunniksi, hallinta palautuu, alat ajatella raittiisti. "Okei, en ole mikään idiootti, en tee typeriä asioita, olen aika hyödyllinen ihminen." Kun olet pystynyt vakuuttamaan itsesi, on aika siirtyä seuraavaan vaiheeseen: ymmärtämään mitä tapahtui. Sinua vastaan ​​hyökättiin, hyökkäys tuli sieltä, mistä et odottanut sitä, se oli epärehellinen, alhainen väijytys. Tämä on huono. Seuraava askel on ymmärtää, miksi hyökkääjä tarvitsi tätä. Oikeasti, miksi? Ehkä siksi, että hän itse on raivoissaan? Miksi hän on vihainen? Esimerkiksi siksi, että hän sotki itsensä eikä voi ottaa vastuuta? Tämä on tapa käsitellä koko tilannetta huolellisesti. Mutta tämä vaatii liikkumavaraa, sanallista tilaa. Ensimmäinen askel on katkaista suullinen kontakti. Vältä keskustelua sanoilla. Peruuta se, kävele pois mahdollisimman nopeasti. Jos kyseessä on puhelinkeskustelu, katkaise vain puhelin – tämän taidon opin kommunikoimalla ex-vaimoni kanssa. Jos keskustelu ei johda mihinkään hyvään, sano vain "näkemiin" ja sulje puhelin. Puhelimen toiselta puolelta: "blaa blaa", vastaat: "joo, hei!" ja katkaise puhelu. Lopetat vain keskustelun. Viiden minuutin kuluttua, kun kyky ajatella järkevästi palaa sinulle, olet hieman jäähtynyt, on mahdollista ajatella kaikkea, mitä tapahtui ja mitä tapahtuu seuraavaksi. Ja aloita harkitun vastauksen muotoilu sen sijaan, että reagoisit vain tunteella. Minulle itsetuntemuksen läpimurto oli juuri se, etten voi puhua henkisessä stressissä. Poistuminen tästä tilasta, miettiminen ja suunnittelu kuinka vastata ja kompensoida ongelmia - nämä ovat oikeat askeleet tilanteessa, jossa et pysty puhumaan. Helpoin tapa on paeta tilannetta, jossa emotionaalinen stressi ilmenee, ja yksinkertaisesti lopettaa osallistuminen tähän stressiin. Sen jälkeen pystyt ajattelemaan, kun voit ajatella, tulet kykeneväksi puhumaan ja niin edelleen.

Muuten, oikeudessa vastustaja asianajaja yrittää tehdä tämän sinulle - nyt on selvää, miksi. Koska hänellä on kyky tukahduttaa sinut sellaiseen tilaan, että et voi edes lausua esimerkiksi nimeäsi. Todella todellisessa mielessä et voi puhua. Jos näin tapahtuu sinulle ja tiedät joutuvasi paikasta, jossa sanataistelut raivoavat, sellaisessa paikassa kuin tuomioistuin, voit tulla asianajajasi kanssa. Lakimies puolustaa sinua ja lopettaa sanallisen hyökkäyksen ja tekee sen täysin laillisella tavalla, ja kadonnut Zen-avaruus palaa sinulle. Esimerkiksi minun piti soittaa perheelleni pari kertaa, tuomari oli melko ystävällinen tästä, mutta vastapuolen asianajaja huusi ja huusi minulle, en saanut edes sanaa reunaan. Näissä tapauksissa sovittelijan käyttö toimii minulle parhaiten. Sovittelija pysäyttää kaiken tämän jatkuvana virtana päällesi kaatuvan paineen, löydät tarvittavan Zen-tilan ja sen mukana puhumiskyky palaa. Tämä on kokonainen tiedon ala, jossa on paljon tutkittavaa, paljon itsessäsi löydettävää, ja kaikki tämä muuttuu korkean tason strategisiksi päätöksiksi, jotka ovat erilaisia ​​eri ihmisille. Joillakin ihmisillä ei ole yllä kuvattuja ongelmia; yleensä ammattimyyjillä niitä ei ole. Kaikilla näillä sanoilla elantonsa ansaitsevilla ihmisillä - kuuluisilla laulajilla, runoilijoilla, uskonnollisilla johtajilla ja poliitikoilla on aina jotain sanottavaa. Heillä ei ole tällaisia ​​ongelmia, mutta minulla on.

Andrew: Se oli... odottamatonta. Hienoa, olemme jo puhuneet paljon ja on aika lopettaa tämä haastattelu. Tapaamme ehdottomasti konferenssissa ja voimme jatkaa tätä vuoropuhelua. Nähdään Hydrassa!

Voit jatkaa keskusteluasi Cliffin kanssa Hydra 2019 -konferenssissa, joka pidetään 11.-12 Pietarissa. Hän tulee raportin kanssa "Azul Hardware Transaction Memory -kokemus". Lippuja voi ostaa virallisella verkkosivustolla.

Lähde: will.com

Lisää kommentti