Suurepärane intervjuu Cliff Clickiga, Java-keelse JIT-i koostamise isaga

Suurepärane intervjuu Cliff Clickiga, Java-keelse JIT-i koostamise isagaCliff Click — Cratuse CTO (IoT andurid protsesside täiustamiseks), mitmete edukate väljumistega idufirmade (sh Rocket Realtime School, Neurensic ja H2O.ai) asutaja ja kaasasutaja. Cliff kirjutas oma esimese kompilaatori 15-aastaselt (Pascal TRS Z-80 jaoks)! Ta on enim tuntud oma töö eest C2-ga Javas (IR sõlmede meri). See kompilaator näitas maailmale, et JIT suudab toota kvaliteetset koodi, mis oli üheks teguriks Java kui ühe peamise kaasaegse tarkvaraplatvormi tekkimisel. Seejärel aitas Cliff Azul Systemsil luua puhta Java-tarkvaraga 864-tuumalise suurarvuti, mis toetas 500-gigabaidise hunniku GC-pause 10 millisekundi jooksul. Üldiselt suutis Cliff töötada JVM-i kõigi aspektidega.

 
See habrapost on suurepärane intervjuu Cliffiga. Räägime järgmistel teemadel:

  • Üleminek madala taseme optimeerimisele
  • Kuidas teha suurt ümbertöötlust
  • Kulude mudel
  • Madala taseme optimeerimise koolitus
  • Praktilised näited jõudluse parandamisest
  • Miks luua oma programmeerimiskeel
  • Performance Engineer'i karjäär
  • Tehnilised väljakutsed
  • Natuke registri eraldamisest ja mitmest tuumast
  • Suurim väljakutse elus

Intervjuu viivad läbi:

  • Andrei Satarin Amazoni veebiteenustest. Oma karjääri jooksul õnnestus tal töötada täiesti erinevates projektides: ta katsetas NewSQL-i hajutatud andmebaasi Yandexis, pilvetuvastussüsteemi Kaspersky Labis, mitme mängijaga mängu Mail.ru-s ja valuutahindade arvutamise teenust Deutsche Bankis. Huvitatud suuremahuliste tausta- ja hajutatud süsteemide testimisest.
  • Vladimir Sitnikov Netcrackerist. Kümme aastat tööd NetCracker OS-i – tarkvara, mida telekommunikatsioonioperaatorid kasutavad võrgu- ja võrguseadmete haldusprotsesside automatiseerimiseks – jõudluse ja mastaapsuse kallal. Huvitatud Java ja Oracle Database'i jõudluse probleemidest. Rohkem kui tosina ametliku PostgreSQL JDBC draiveri jõudluse täiustuse autor.

Üleminek madala taseme optimeerimisele

Andrew: Olete JIT-i koostamise, Java ja üldse esitustöö maailmas suur nimi, eks? 

Kalju: See on nii!

Andrew: Alustame mõne üldise küsimusega esinemistöö kohta. Mida arvate valikust kõrge ja madala taseme optimeerimise vahel, näiteks protsessori tasemel töötamine?

Kalju: Jah, siin on kõik lihtne. Kiireim kood on see, mis kunagi ei käivitu. Seetõttu peate alati alustama kõrgelt tasemelt, töötama algoritmide kallal. Parem O-tähistus ületab halvemat O-tähistust, kui ei sekku mõned piisavalt suured konstandid. Madala tasemega asjad jäävad viimaseks. Tavaliselt on see madal tase, kui olete oma ülejäänud pinu piisavalt hästi optimeerinud ja huvitavaid asju on veel alles. Kuidas aga alustada kõrgelt tasemelt? Kust sa tead, et on tehtud piisavalt kõrgetasemelist tööd? Noh... mitte mingil juhul. Valmisretsepte pole. Peate probleemist aru saama, otsustama, mida kavatsete teha (et mitte tulevikus tarbetuid samme astuda) ja seejärel saate paljastada profiili koostaja, kes võib midagi kasulikku öelda. Mingil hetkel taipad ka ise, et oled ebavajalikest asjadest lahti saanud ja on aeg teha vähest peenhäälestust. See on kindlasti eriline kunst. On palju inimesi, kes teevad mittevajalikke asju, kuid liiguvad nii kiiresti, et neil pole aega tootlikkuse pärast muretseda. Aga seda seni, kuni küsimus otse välja kerkib. Tavaliselt 99% juhtudest ei huvita kedagi, mida ma teen, kuni hetkeni, mil kriitilisel teel tuleb mõni oluline asi, millest keegi ei hooli. Ja siin hakkavad kõik sind norima teemal "miks see algusest peale ideaalselt ei töötanud". Üldiselt on jõudluses alati midagi parandada. Kuid 99% juhtudest pole teil müügivihjeid! Sa lihtsalt üritad midagi tööle panna ja selle käigus saad aru, mis on oluline. Kunagi ei või ette teada, et see tükk peab olema täiuslik, nii et tegelikult tuleb kõiges täiuslik olla. Kuid see on võimatu ja te ei tee seda. Alati tuleb palju asju parandada – ja see on täiesti normaalne.

Kuidas teha suurt ümbertöötlust

Andrew: Kuidas te etenduse kallal töötate? See on läbiv probleem. Kas olete näiteks kunagi pidanud tegelema probleemidega, mis tulenevad paljude olemasolevate funktsionaalsuste ristumisvõimalustest?

Kalju: Püüan seda vältida. Kui ma tean, et jõudlus on probleem, mõtlen sellele enne kodeerimise alustamist, eriti andmestruktuuride puhul. Kuid sageli avastate selle kõige hiljem väga hiljem. Ja siis tuleb minna äärmuslike meetmete juurde ja teha seda, mida ma nimetan “ümber kirjutama ja vallutama”: tuleb haarata piisavalt suur tükk. Osa koodist tuleb jõudlusprobleemide või millegi muu tõttu ikkagi ümber kirjutada. Olenemata koodi ümberkirjutamise põhjusest, on peaaegu alati parem kirjutada suurem tükk kui väiksem tükk. Sel hetkel hakkavad kõik hirmust värisema: "oh issand, sa ei saa nii palju koodi puudutada!" Kuid tegelikult töötab see lähenemine peaaegu alati palju paremini. Peate kohe võtma suure probleemi, joonistama selle ümber suure ringi ja ütlema: ma kirjutan kõik ringi sees ümber. Ääris on palju väiksem kui selle sees olev sisu, mis vajab väljavahetamist. Ja kui selline piiride piiritlemine võimaldab sees oleva töö suurepäraselt ära teha, on käed vabad, tee, mis tahad. Kui olete probleemist aru saanud, on ümberkirjutamise protsess palju lihtsam, nii et võtke palju näksi!
Samal ajal, kui teete suure ümberkirjutuse ja mõistate, et jõudlus on probleem, võite selle pärast kohe muretsema hakata. See muutub tavaliselt lihtsateks asjadeks, nagu "ära kopeeri andmeid, halda andmeid nii lihtsalt kui võimalik, tehke need väikeseks." Suurte ümberkirjutuste puhul on jõudluse parandamiseks standardsed viisid. Ja need tiirlevad peaaegu alati andmete ümber.

Kulude mudel

Andrew: Ühes podcastis rääkisite kulumudelitest tootlikkuse kontekstis. Kas saate selgitada, mida te selle all mõtlesite?

Kalju: Kindlasti. Olen sündinud ajastul, mil protsessori jõudlus oli äärmiselt oluline. Ja see ajastu naaseb taas – saatus pole ilma irooniata. Hakkasin elama kaheksabitiste masinate ajal, minu esimene arvuti töötas 256 baidiga. Täpselt baite. Kõik oli väga väike. Juhised tuli üle lugeda ja kui hakkasime programmeerimiskeelte virnast ülespoole liikuma, võtsid keeled üha enam oma osa. Seal olid Assembler, seejärel Basic, seejärel C ja C hoolitses paljude üksikasjade eest, nagu registri eraldamine ja juhiste valik. Aga seal oli kõik üsna selge ja kui ma teeksin kursori muutuja eksemplarile, siis saan koormuse ja selle juhise maksumus on teada. Riistvara toodab teatud arvu masinatsükleid, nii et erinevate asjade täitmiskiirust saab arvutada lihtsalt kõigi käitatavate juhiste liitmisel. Iga võrdlemise/testimise/haru/helista/laadimise/poodi võiks liita ja öelda: see on teie jaoks täitmise aeg. Jõudluse parandamisega töötades pöörate kindlasti tähelepanu sellele, millised numbrid vastavad väikestele kuumadele tsüklitele. 
Aga niipea, kui lülitud üle Javale, Pythonile ja sarnastele asjadele, eemaldute väga kiiresti madala tasemega riistvarast. Kui palju maksab Javas getterile helistamine? Kui JIT HotSpotis on õige sisseehitatud, see laaditakse, kuid kui see seda ei teinud, on see funktsioonikutse. Kuna kõne on kuumal tsüklil, alistab see kõik muud selle ahela optimeerimised. Seetõttu on tegelikud kulud palju suuremad. Ja te kaotate kohe võimaluse vaadata kooditükki ja mõista, et peaksime seda täitma protsessori taktsageduse, kasutatava mälu ja vahemälu osas. See kõik muutub huvitavaks vaid siis, kui etendusse päriselt sisse satud.
Nüüd leiame end olukorrast, kus protsessori kiirus pole kümnendi jooksul peaaegu kasvanud. Vanad ajad on tagasi! Enam ei saa loota heale ühe keermega jõudlusele. Aga kui sa järsku paralleelarvutusse satud, on see uskumatult raske, kõik vaatavad sind nagu James Bondi. Kümnekordsed kiirendused tekivad siin tavaliselt kohtades, kus keegi on midagi sassi ajanud. Samaaegsus nõuab palju tööd. Selle XNUMX-kordse kiirendamise saamiseks peate mõistma kulumudelit. Mis ja kui palju maksab? Ja selleks peate mõistma, kuidas keel sobib selle aluseks olevale riistvarale.
Martin Thompson valis oma ajaveebi jaoks suurepärase sõna Mehaaniline sümpaatia! Peate mõistma, mida riistvara kavatseb teha, kuidas see seda täpselt teeb ja miks ta seda teeb. Seda kasutades on üsna lihtne hakata juhiseid loendama ja aru saama, kuhu täitmisaeg läheb. Kui sul pole vastavat väljaõpet, siis otsid lihtsalt musta kassi pimedasse ruumi. Näen inimesi pidevalt jõudlust optimeerimas, kellel pole õrna aimugi, mida kuradit nad teevad. Nad kannatavad palju ega tee palju edusamme. Ja kui ma võtan sama koodilõigu, libistan sisse paar väikest häkki ja kiirendan viis- või kümnekordset kiirust, on need sellised: noh, see pole aus, me juba teadsime, et sa oled parem. Hämmastav. Millest ma räägin... kulumudel räägib sellest, millist koodi sa kirjutad ja kui kiiresti see suures pildis keskmiselt jookseb.

Andrew: Ja kuidas sellist helitugevust peas hoida? Kas see saavutatakse suurema kogemusega või? Kust selline kogemus pärit on?

Kalju: Noh, ma ei saanud oma kogemust kõige lihtsamal viisil. Programmeerisin Assemblysse aegadel, mil saite aru igast juhisest. Kõlab tobedalt, aga sellest ajast on Z80 juhiste komplekt alati pähe, mällu jäänud. Ma ei mäleta inimeste nimesid minuti jooksul pärast rääkimist, kuid mäletan 40 aastat tagasi kirjutatud koodi. See on naljakas, see näeb välja nagu sündroom"idioot teadlane'.

Madala taseme optimeerimise koolitus

Andrew: Kas on lihtsam viis sisse pääseda?

Kalju: Jah ja ei. Riistvara, mida me kõik kasutame, pole aja jooksul nii palju muutunud. Kõik kasutavad x86, välja arvatud Armi nutitelefonid. Kui te ei tee mingit raskekujulist manustamist, teete sama asja. Olgu, järgmine. Ka juhised pole sajandeid muutunud. Peate minema ja Assemblysse midagi kirjutama. Mitte palju, aga piisavalt, et aru saada. Sa naeratad, aga ma räägin täiesti tõsiselt. Peate mõistma keele ja riistvara vastavust. Pärast seda peate minema natuke kirjutama ja tegema väikese mänguasjakeele jaoks väikese mänguasjade kompilaatori. Mänguasjalaadne tähendab, et see tuleb valmistada mõistliku aja jooksul. See võib olla ülilihtne, kuid see peab genereerima juhiseid. Käsu genereerimine aitab teil mõista kõigi kirjutatava kõrgetasemelise koodi ja riistvaras töötava masinkoodi vahelise silla kulumudelit. See kirjavahetus põletatakse kompilaatori kirjutamise ajal ajju. Isegi kõige lihtsam kompilaator. Pärast seda võib hakata vaatama Java-d ja seda, et selle semantiline kuristik on palju sügavamal ning sildu üle selle on palju keerulisem ehitada. Javas on palju keerulisem aru saada, kas meie sild osutus heaks või halvaks, mis põhjustab selle lagunemise ja mis mitte. Kuid teil on vaja mingit lähtepunkti, kus vaatate koodi ja mõistate: "jah, see getter tuleks iga kord sisse lülitada." Ja siis selgub, et mõnikord see juhtub, välja arvatud olukord, kus meetod muutub liiga suureks ja JIT hakkab kõike sisse panema. Selliste kohtade toimivust saab koheselt ennustada. Tavaliselt töötavad getterid hästi, kuid siis vaatate suuri kuumsilmusi ja mõistate, et seal vedelevad mõned funktsioonikutsed, mis ei tea, mida nad teevad. See on getterite laialdase kasutuse probleem, põhjus, miks neid ei sisestata, on see, et pole selge, kas need on getterid. Kui teil on üliväike koodibaas, võite selle lihtsalt meelde jätta ja siis öelda: see on getter ja see on seadja. Suures koodibaasis elab iga funktsioon oma ajalugu, mida üldiselt keegi ei tea. Profileerija ütleb, et me kaotasime 24% ajast mõnel tsüklil ja selleks, et mõista, mida see silmus teeb, peame vaatama iga funktsiooni sees. Seda on võimatu mõista ilma funktsiooni uurimata ja see aeglustab mõistmisprotsessi tõsiselt. Sellepärast ma gettereid ja settereid ei kasuta, olen jõudnud uuele tasemele!
Kust saada kulumudelit? No midagi võib muidugi lugeda... Aga ma arvan, et parim viis on tegutseda. Väikese kompilaatori tegemine on parim viis kulumudelist aru saamiseks ja selle enda pähe sobitamiseks. Väike kompilaator, mis sobiks mikrolaineahju programmeerimiseks, on algaja ülesanne. Noh, ma mõtlen, et kui sul on juba programmeerimisoskused, siis sellest peaks piisama. Kõik need asjad, näiteks mingi algebralise avaldisena oleva stringi sõelumine, sealt õiges järjekorras matemaatiliste toimingute juhiste eraldamine, registritest õigete väärtuste võtmine – kõik see toimub korraga. Ja kui te seda teete, jääb see teie ajju. Ma arvan, et kõik teavad, mida kompilaator teeb. Ja see annab ülevaate kulumudelist.

Praktilised näited jõudluse parandamisest

Andrew: Millele veel tootlikkuse kallal töötades tähelepanu pöörata?

Kalju: Andmestruktuurid. Muide, jah, ma pole pikka aega neid tunde andnud... Raketikool. See oli lõbus, kuid see nõudis palju pingutust ja mul on ka elu! OKEI. Niisiis tõin ühes suures ja huvitavas tunnis “Kuhu teie jõudlus läheb” õpilastele näite: CSV-failist loeti kaks ja pool gigabaiti fintechi andmeid ja siis tuli arvutada müüdud toodete arv. . Regulaarsed puukide turuandmed. Alates 70ndatest on tekstivormingusse teisendatud UDP-paketid. Chicago kaubabörs – kõikvõimalikud asjad nagu või, mais, sojaoad, sellised asjad. Tuli lugeda need tooted, tehingute arv, keskmine raha ja kaupade liikumise maht jne. See on üsna lihtne kauplemismatemaatika: leidke tootekood (see on räsitabelis 1-2 tähemärki), hankige summa, lisage see ühte kauplemiskomplektidest, lisage maht, lisage väärtus ja paar muud asja. Väga lihtne matemaatika. Mänguasja teostus oli väga arusaadav: kõik on failis, ma loen faili läbi ja liigun läbi, jagades üksikud kirjed Java stringideks, otsides neist vajalikke asju ja liites need kokku vastavalt ülalkirjeldatud matemaatikale. Ja see töötab madalal kiirusel.

Selle lähenemisviisi puhul on ilmselge, mis toimub, ja paralleelarvutus ei aita, eks? Selgub, et jõudluse viiekordne tõus on saavutatav lihtsalt õigete andmestruktuuride valimisel. Ja see üllatab isegi kogenud programmeerijaid! Minu konkreetsel juhul oli trikk selles, et te ei tohiks teha mälujaotust kuuma tsüklina. Noh, see pole kogu tõde, kuid üldiselt - te ei tohiks esile tõsta "üks kord X-is", kui X on piisavalt suur. Kui X on kaks ja pool gigabaiti, ei tohiks te määrata midagi “üks kord tähe kohta”, “üks kord rea kohta” või “üks kord välja kohta”, midagi sellist. See on koht, kus aega veedetakse. Kuidas see üldse töötab? Kujutage ette, et ma helistan String.split() või BufferedReader.readLine(). Readline loob stringi baitide hulgast, mis tulid üle võrgu, üks kord iga rea ​​jaoks, iga sadade miljonite ridade jaoks. Võtan selle rea, analüüsin ja viskan minema. Miks ma selle ära viskan - noh, ma olen seda juba töötlenud, see on kõik. Nii et iga nendest 2.7G-st loetud baidi kohta kirjutatakse reale kaks märki, see tähendab juba 5.4G, ja ma ei vaja neid enam millekski, nii et nad visatakse minema. Kui vaadata mälu ribalaiust, siis laadime 2.7G, mis protsessoris läbib mälu ja mälusiini ja seejärel saadetakse kaks korda rohkem mälus lebavale liinile ja see kõik kulub iga uue rea loomisel. Aga ma pean seda lugema, riistvara loeb seda, isegi kui kõik on hiljem narmendav. Ja ma pean selle üles kirjutama, kuna lõin rea ja vahemälud on täis - vahemälu ei mahu 2.7G. Seega loen iga loetud baidi kohta veel kaks baiti ja kirjutan veel kaks baiti ning lõpuks on nende suhe 4:1 – selle suhtega raiskame mälu ribalaiust. Ja siis selgub, et kui ma seda teen String.split() – see pole viimane kord, kui ma seda teen, sees võib olla veel 6-7 põldu. Klassikaline CSV-koodi lugemise ja seejärel stringide sõelumise tulemuseks on mälu ribalaiuse raiskamine umbes 14:1 võrreldes sellega, mida te tegelikult sooviksite. Kui viskate need valikud ära, saate viiekordse kiiruse.

Ja see polegi nii raske. Kui vaatate koodi õige nurga alt, muutub kõik probleemist aru saades üsna lihtsaks. Mälu eraldamist ei tohiks täielikult lõpetada: ainuke probleem on selles, et eraldate midagi ja see sureb koheselt ning selle käigus põletatakse ära oluline ressurss, milleks antud juhul on mälu ribalaius. Ja kõik see toob kaasa tootlikkuse languse. x86-l peate tavaliselt protsessoritsükleid aktiivselt põletama, kuid siin põletasite kogu mälu palju varem. Lahenduseks on heitmete hulga vähendamine. 
Teine osa probleemist on see, et kui käivitate profiilija siis, kui mäluriba saab otsa, siis ootate tavaliselt vahemälu tagasitulekut, sest see on täis prügi, mille te just tootsite, kõik need read. Seetõttu muutub iga laadimine või poe toiming aeglaseks, kuna need põhjustavad vahemälu vahelejäämist - kogu vahemälu on muutunud aeglaseks, oodates, kuni prügi sealt lahkub. Seetõttu näitab profileerija lihtsalt sooja juhuslikku müra, mis on määritud kogu tsükli ulatuses – koodis ei ole eraldi kuuma juhiseid ega kohta. Ainult müra. Ja kui vaadata GC tsükleid, siis need on kõik Young Generation ja ülikiired – maksimaalselt mikro- või millisekundites. Lõppude lõpuks sureb kogu see mälestus silmapilkselt. Eraldate miljardeid gigabaite ja ta lõikab need, lõikab ja lõikab uuesti. Kõik see juhtub väga kiiresti. Selgub, et seal on odavad GC tsüklid, soe müra kogu tsükli vältel, aga tahame saada 5x kiirendust. Sel hetkel peaks midagi peas sulguma ja kõlama: "miks see nii on?!" Mäluriba ületäitumist klassikalises siluris ei kuvata; peate käivitama riistvara jõudluse loenduri siluri ja nägema seda ise ja otse. Kuid seda ei saa nende kolme sümptomi põhjal otseselt kahtlustada. Kolmas sümptom on see, kui vaatate, mida esile tõstate, küsite profiili koostajalt ja ta vastab: "Te tegite miljard rida, kuid GC töötas tasuta." Niipea kui see juhtub, mõistate, et olete loonud liiga palju objekte ja põletanud kogu mäluraja. Selle väljaselgitamiseks on viis, kuid see pole ilmne. 

Probleem on andmestruktuuris: kõige juhtuva aluseks olev tühi struktuur, see on liiga suur, kettal on 2.7G, nii et sellest asjast koopia tegemine on väga ebasoovitav - soovite selle kohe võrgubaidipuhvrist laadida. registritesse, et mitte viis korda edasi-tagasi reale lugeda-kirjutada. Kahjuks ei anna Java teile vaikimisi sellist teeki JDK osana. Aga see on triviaalne, eks? Põhimõtteliselt on need 5–10 koodirida, mida kasutatakse teie enda puhverdatud stringilaaduri rakendamiseks, mis kordab stringiklassi käitumist, olles samas aluseks oleva baidipuhvri ümbris. Selle tulemusena selgub, et töötate peaaegu nagu stringidega, kuid tegelikult liiguvad seal puhvrile viivad osutid ja tooreid baite ei kopeerita kuhugi ja seega kasutatakse samu puhvreid ikka ja jälle ning operatsioonisüsteem võtab hea meelega enda peale need asjad, mille jaoks see on loodud, nagu nende baitpuhvrite varjatud topeltpuhver, ja te ei lihvi enam läbi lõputu tarbetute andmete voo. Muide, kas saate aru, et GC-ga töötades on garanteeritud, et pärast viimast GC tsüklit pole iga mälueraldus protsessorile nähtav? Seetõttu ei saa see kõik vahemälus olla ja siis tekib 100% garanteeritud möödalaskmine. Kursoriga töötades võtab x86-l registri mälust lahutamine 1-2 kella tsüklit ja niipea kui see juhtub, maksate, maksate, maksate, sest mälu on sisse lülitatud Üheksa vahemälu – ja see on mälu eraldamise kulu. Tõeline väärtus.

Teisisõnu, andmestruktuure on kõige raskem muuta. Ja kui mõistate, et olete valinud vale andmestruktuuri, mis hiljem jõudlust hävitab, on tavaliselt palju tööd teha, kuid kui te seda ei tee, lähevad asjad hullemaks. Kõigepealt tuleb mõelda andmestruktuuridele, see on oluline. Peamine kulu langeb siin rasvadele andmestruktuuridele, mida hakatakse kasutama stiilis "Ma kopeerisin andmestruktuuri X andmestruktuuri Y, sest mulle meeldib Y kuju rohkem." Kuid kopeerimisoperatsioon (mis tundub odav) raiskab tegelikult mälu ribalaiust ja sinna maetakse kogu raisatud täitmise aeg. Kui mul on hiiglaslik JSON-string ja ma tahan selle muuta POJO-de struktureeritud DOM-puuks või millekski muuks, põhjustab selle stringi sõelumine ja POJO loomine ning seejärel POJO-le hiljem uuesti juurde pääsemine tarbetuid kulusid – see on mitte odav. Välja arvatud juhul, kui jooksed ümber POJOde palju sagedamini kui jooksed ümber nööri. Selle asemel võite proovida stringi dekrüpteerida ja sealt ekstraheerida ainult seda, mida vajate, ilma seda POJO-ks muutmata. Kui see kõik juhtub rajal, millelt on vaja maksimaalset jõudlust, teie jaoks pole POJO-sid, peate kuidagi otse liini sisse kaevama.

Miks luua oma programmeerimiskeel

Andrew: Ütlesite, et kulumudeli mõistmiseks on vaja kirjutada oma väike keel...

Kalju: Mitte keel, vaid koostaja. Keel ja kompilaator on kaks erinevat asja. Kõige olulisem erinevus on teie peas. 

Andrew: Muide, minu teada katsetate oma keelte loomisega. Milleks?

Kalju: Sest ma saan! Olen poolpensionär, nii et see on minu hobi. Olen terve elu rakendanud teiste inimeste keeli. Samuti töötasin palju oma kodeerimisstiili kallal. Ja ka sellepärast, et näen probleeme teistes keeltes. Näen, et tuttavate asjade tegemiseks on paremaid viise. Ja ma kasutaksin neid. Olen lihtsalt väsinud nägemast probleeme endas, Javas, Pythonis ja mis tahes muus keeles. Kirjutan nüüd React Native'is, JavaScriptis ja Elmis hobina, mis ei ole seotud pensionile jäämisega, vaid aktiivse tööga. Kirjutan ka Pythonis ja suure tõenäosusega jätkan Java taustaprogrammide masinõppe kallal töötamist. Populaarseid keeli on palju ja neil kõigil on huvitavaid funktsioone. Igaüks on omamoodi hea ja võite proovida kõiki neid funktsioone kokku viia. Niisiis, ma uurin asju, mis mind huvitavad, keele käitumist, proovin välja mõelda mõistlikku semantikat. Ja siiani on see mul õnnestunud! Hetkel olen hädas mälusemantikaga, sest tahan, et see oleks nagu C ja Java puhul ning saaks tugeva mälumudeli ja mälu semantika laadimiste ja salvestamiste jaoks. Samal ajal kasutage automaatset tüübi järeldust nagu Haskellis. Siin proovin segada Haskelli tüüpi järeldusi mälutööga nii C- kui Java-vormingus. Seda olen ma näiteks viimased 2-3 kuud teinud.

Andrew: Kui ehitate keele, mis võtab teistest keeltest paremaid aspekte, kas arvate, et keegi teeb vastupidist: võtab teie ideed ja kasutab neid?

Kalju: Täpselt nii ilmuvad uued keeled! Miks Java sarnaneb C-ga? Kuna C-l oli hea süntaks, millest kõik aru said, ja Java oli sellest süntaksist inspireeritud, lisades tüübiturvalisuse, massiivipiiride kontrollimise, GC-d ja nad parandasid ka mõnda asja C-st. Nad lisasid oma. Kuid nad said üsna palju inspiratsiooni, eks? Kõik seisavad nende hiiglaste õlgadel, kes tulid enne sind – nii tehakse edusamme.

Andrew: Nagu ma aru saan, on teie keel mälukindel. Kas olete mõelnud sellise asja rakendamisele nagu Rustilt laenata? Kas sa oled teda vaadanud, mida sa temast arvad?

Kalju: Noh, ma olen kirjutanud C-d juba ammu, kogu selle malloc ja tasuta ning haldasin kogu eluea käsitsi. Teate, 90-95% käsitsi juhitavast elueast on sama struktuuriga. Ja seda käsitsi teha on väga-väga valus. Tahaks, et koostaja lihtsalt räägiks, mis seal toimub ja mida sa oma tegudega saavutasid. Mõne asja puhul teeb laenukontrollija seda juba karbist välja. Ja see peaks automaatselt kuvama teavet, mõistma kõike ja isegi mitte koormama mind selle mõistmise esitamisega. See peab tegema vähemalt lokaalse põgenemisanalüüsi ja ainult siis, kui see ebaõnnestub, siis peab see lisama tüübimärkused, mis kirjeldavad eluiga – ja selline skeem on palju keerulisem kui laenatav kontrollija või mis tahes olemasolev mälukontroll. Valik "kõik on hästi" ja "ma ei saa millestki aru" vahel - ei, midagi paremat peab olema. 
Nii et kui inimene, kes on C-s palju koodi kirjutanud, arvan, et automaatse eluaegse juhtimise tugi on kõige olulisem. Mul on ka kõrini sellest, kui palju Java mälu kasutab ja peamine kaebus on GC. Kui eraldate Java-s mälu, ei saa te tagasi viimases GC-tsüklis lokaalset mälu. Täpsema mäluhaldusega keelte puhul see nii ei ole. Kui helistate mallocile, saate kohe mälu, mida tavaliselt just kasutati. Tavaliselt teete mäluga mingeid ajutisi asju ja tagastate selle kohe tagasi. Ja see naaseb kohe malloci basseini ja järgmine malloci tsükkel tõmbab selle uuesti välja. Seetõttu väheneb tegelik mälukasutus antud ajahetkel elavate objektide kogumile, millele lisanduvad lekked. Ja kui kõik ei leki täiesti sündsusetul viisil, satub suurem osa mälust vahemällu ja protsessorisse ning see töötab kiiresti. Aga nõuab palju käsitsi mäluhaldust mallociga ja tasuta helistamist õiges järjekorras, õiges kohas. Rooste saab sellega üksi korralikult hakkama ja annab paljudel juhtudel veelgi parema jõudluse, kuna mälukulu on kitsendatud ainult praegusele arvutustele – selle asemel, et oodata järgmist GC-tsüklit, et mälu vabastada. Selle tulemusena saime väga huvitava viisi jõudluse parandamiseks. Ja päris võimas – ma mõtlesin selliseid asju fintechi jaoks andmete töötlemisel ja see võimaldas mul umbes viis korda kiirendada. See on päris suur tõuge, eriti maailmas, kus protsessorid ei muutu kiiremaks ja me ootame endiselt täiustusi.

Performance Engineer'i karjäär

Andrew: Tahaksin küsida ka karjääri kohta üldiselt. Tõusite esile JIT-tööga HotSpotis ja kolisite seejärel Azulisse, mis on samuti JVM-i ettevõte. Kuid me töötasime juba rohkem riistvara kui tarkvara kallal. Ja siis läksid nad järsku üle suurandmetele ja masinõppele ning seejärel pettuste tuvastamisele. Kuidas see juhtus? Need on väga erinevad arenguvaldkonnad.

Kalju: Olen programmeerimisega tegelenud üsna pikka aega ja jõudnud läbida palju erinevaid tunde. Ja kui inimesed ütlevad: "Oh, sina oled see, kes Java jaoks JIT-i tegi!", on see alati naljakas. Kuid enne seda töötasin PostScripti klooni kallal – keele, mida Apple kunagi oma laserprinterite jaoks kasutas. Ja enne seda tegin Forthi keele juurutuse. Arvan, et minu jaoks on ühine teema tööriistade arendamine. Olen terve elu teinud tööriistu, millega teised inimesed oma lahedaid programme kirjutavad. Kuid tegelesin ka operatsioonisüsteemide, draiverite, kernelitaseme silurite, OS-i arenduskeelte väljatöötamisega, mis algas triviaalsena, kuid muutus aja jooksul üha keerulisemaks. Kuid põhiteema on ikkagi tööriistade arendamine. Suur osa minu elust möödus Azuli ja Suni vahel ning see puudutas Java. Aga kui jõudsin suurandmete ja masinõppe juurde, panin oma uhke mütsi pähe ja ütlesin: "Oh, nüüd on meil mittetriviaalne probleem ja toimub palju huvitavaid asju ja inimesed teevad asju." See on suurepärane arengutee.

Jah, ma tõesti armastan hajutatud andmetöötlust. Minu esimene töökoht oli C-i tudengina reklaamiprojekti juures. See oli hajutatud andmetöötlus Zilog Z80 kiipidel, mis kogusid andmeid tõelise analooganalüsaatori poolt toodetud analoog-OCR jaoks. See oli lahe ja täiesti hull teema. Kuid tekkisid probleemid, mõnda osa ei tuvastatud õigesti, nii et tuli võtta pilt välja ja näidata inimesele, kes oskas juba silmadega lugeda ja raporteerida, mida see ütles, ja seetõttu olid töökohad andmetega ja need tööd oli oma keel. Seal oli taustaprogramm, mis seda kõike töötles - Z80-d töötavad paralleelselt vt100 terminalidega - üks inimese kohta ja Z80-l oli paralleelne programmeerimismudel. Mõned ühised mälutükid, mida jagavad kõik tähekonfiguratsioonis olevad Z80-d; Jagati ka tagaplaati ja pool RAM-ist jagati võrgu sees ja teine ​​pool oli privaatne või läks millelegi muule. Mõtteliselt keeruline paralleelselt hajutatud süsteem jagatud... pooljagatud mäluga. Millal see oli... Ma isegi ei mäleta, kuskil 80ndate keskel. Päris ammu. 
Jah, oletame, et 30 aastat on üsna pikk aeg. Hajaarvutusega seotud probleemid on eksisteerinud üsna pikka aega, inimesed on pikka aega sõdinud Beowulf- klastrid. Sellised klastrid näevad välja sellised... Näiteks: seal on Ethernet ja sinu kiire x86 on selle Ethernetiga ühendatud ja nüüd tahad saada võlts ühismälu, sest hajusarvutuskodeerimist ei osanud siis keegi teha, see oli liiga raske ja seetõttu oli oli x86 kaitsemälu lehtedega võlts ühismälu ja kui sa sellele lehele kirjutasid, siis ütlesime teistele protsessoritele, et kui nad pääsevad samale ühismälule, tuleb see sinult laadida ja seega midagi toetava protokolli taolist. ilmus vahemälu sidusus ja tarkvara selle jaoks. Huvitav kontseptsioon. Tegelik probleem oli muidugi milleski muus. Kõik see toimis, kuid teil tekkisid kiiresti jõudlusprobleemid, sest keegi ei mõistnud jõudlusmudeleid piisavalt heal tasemel - millised mälu juurdepääsu mustrid seal olid, kuidas veenduda, et sõlmed ei pingi üksteist lõputult jne.

Mida ma H2O-s leidsin, on see, et arendajad ise vastutavad selle eest, kus paralleelsus on peidetud ja kus mitte. Mõtlesin välja kodeerimismudeli, mis tegi suure jõudlusega koodi kirjutamise lihtsaks ja lihtsaks. Kuid aeglaselt töötava koodi kirjutamine on keeruline, see näeb halb välja. Peate tõsiselt proovima kirjutada aeglast koodi, peate kasutama mittestandardseid meetodeid. Pidurikood on esmapilgul näha. Selle tulemusel kirjutatakse tavaliselt kiiresti töötavat koodi, kuid ühismälu puhul tuleb välja mõelda, mida teha. Kõik see on seotud suurte massiividega ja sealne käitumine sarnaneb paralleelse Java mittelenduvate suurte massiividega. Kujutage ette, et kaks lõime kirjutavad paralleelsele massiivile, üks neist võidab ja teine ​​vastavalt kaotab, ja te ei tea, kumb on kumb. Kui need ei ole muutlikud, võib järjekord olla mis iganes soovite – ja see toimib tõesti hästi. Inimesed hoolivad tõesti toimingute järjestusest, nad panevad volatiili õigetesse kohtadesse ja ootavad mäluga seotud jõudlusprobleeme õigetes kohtades. Vastasel juhul kirjutaksid nad koodi lihtsalt silmuste kujul 1-st N-ni, kus N on mõned triljonid, lootuses, et kõik keerulised juhtumid muutuvad automaatselt paralleelseks – ja see seal ei tööta. Kuid H2O-s pole see ei Java ega Scala; kui soovite, võite seda pidada "Java miinus miinus". See on väga selge programmeerimisstiil ja sarnaneb lihtsa C- või Java-koodi kirjutamisega silmuste ja massiividega. Kuid samal ajal saab mälu töödelda terabaitides. Ma kasutan endiselt H2O-d. Kasutan seda aeg-ajalt erinevates projektides – ja see on ikka kõige kiirem asi, kümneid kordi kiirem kui tema konkurendid. Kui teete suurandmeid veergude andmetega, on H2O-d väga raske ületada.

Tehnilised väljakutsed

Andrew: Mis on olnud teie suurim väljakutse kogu teie karjääri jooksul?

Kalju: Kas me arutame probleemi tehnilist või mittetehnilist osa? Ma ütleksin, et suurimad väljakutsed ei ole tehnilised. 
Mis puutub tehnilistesse väljakutsetesse. Ma lihtsalt võitsin nad. Ma isegi ei tea, mis oli kõige suurem, aga seal oli päris huvitavaid, mis võtsid üsna palju aega, vaimset võitlust. Suni minnes olin kindel, et teen kiire koostaja ja kamp seeniore ütles vastuseks, et see ei õnnestu mul kunagi. Kuid ma läksin seda teed, kirjutasin kompilaatori registri jaoturisse ja see oli üsna kiire. See oli sama kiire kui tänapäevane C1, kuid jaotur oli toona palju aeglasem ja tagantjärele mõeldes oli see suur andmestruktuuri probleem. Mul oli seda vaja graafilise registri jagaja kirjutamiseks ja ma ei mõistnud dilemmat koodi ekspressiivsuse ja kiiruse vahel, mis sellel ajastul eksisteeris ja oli väga oluline. Selgus, et andmestruktuur ületab tavaliselt tolleaegsetel x86-del vahemälu suurust ja seetõttu, kui ma algselt eeldasin, et registri jagaja töötab välja 5-10 protsenti kogu värinaajast, siis tegelikkuses osutus see 50 protsenti.

Mida aeg edasi, seda puhtamaks ja efektiivsemaks muutus kompilaator, enamal juhtudel lõpetas kohutava koodi genereerimise ning jõudlus hakkas üha enam sarnanema C-kompilaatoriga. Kui sa muidugi ei kirjuta mingit jama, mida isegi C ei kiirenda. . Kui kirjutate koodi nagu C, saavutate suurematel juhtudel jõudluse nagu C. Ja mida edasi, seda sagedamini saite koodi, mis asümptootiliselt langes kokku tasemega C, registrieraldaja hakkas välja nägema midagi terviklikku... olenemata sellest, kas teie kood töötab kiiresti või aeglaselt. Jätkasin tööd jaoturiga, et see teeks paremaid valikuid. Ta muutus aina aeglasemaks, kuid andis järjest paremaid tulemusi juhtudel, kui keegi teine ​​hakkama ei saanud. Võiksin sukelduda registrieraldajasse, matta sinna kuu aega tööd ja järsku hakkaks kogu kood 5% kiiremini täitma. Seda juhtus aeg-ajalt ja registrijaoturist sai mingi kunstiteos - kõigile meeldis või vihkas ja akadeemia inimesed esitasid küsimusi teemal “miks kõik nii tehakse”, miks mitte. liini skaneerimine, ja mis vahet sellel on. Vastus on ikka sama: graafiku värvimisel põhinev jaotur pluss väga hoolikas töö puhverkoodiga on võrdne võidurelvaga, parima kombinatsiooniga, mida keegi alistada ei saa. Ja see on üsna ebaselge asi. Kõik muu, mida koostaja seal teeb, on üsna hästi läbi uuritud asjad, kuigi needki on viidud kunsti tasemele. Tegin alati asju, mis pidid koostajast kunstiteose tegema. Kuid miski sellest polnud midagi erakordset – välja arvatud registri jagaja. Trikk on olla ettevaatlik vähendama koormuse all ja kui see juhtub (huvi korral võin üksikasjalikumalt selgitada), tähendab see, et saate agressiivsemalt sisse lüüa, ilma et peaksite esinemisgraafikusse kukkuma. Tol ajal oli hunnik täismahus kompilaatoreid, mis olid riputatud baubide ja viledega, millel olid registrieraldajad, kuid keegi teine ​​ei saanud seda teha.

Probleem on selles, et kui lisate meetodid, mis on allutatud sisestusalale, suurendavad ja suurendavad sisestusala, ületab kasutatavate väärtuste hulk koheselt registrite arvu ja peate neid kärpima. Kriitiline tase saabub tavaliselt siis, kui jagaja loobub ja üks hea lekkekandidaat on teist väärt, müüd mõne üldiselt metsiku asja maha. Sisseehitamise väärtus seisneb selles, et kaotate osa üldkuludest, helistamise ja salvestamise üldkuludest, näete väärtusi sees ja saate neid veelgi optimeerida. Lisamise hind seisneb selles, et moodustub suur hulk reaalajas väärtusi ja kui teie registri jaotur põleb rohkem kui vaja, kaotate kohe. Seetõttu on enamikul jaoturitel probleem: kui inlining ületab teatud joone, hakatakse maailmas kõike kärpima ja tootlikkust saab tualetti alla lasta. Need, kes kompilaatorit juurutavad, lisavad heuristikat: näiteks lõpetage inlining, alustades mõnest piisavalt suurest suurusest, kuna jaotused rikuvad kõik. Nii moodustub sooritusgraafiku murdekoht – sa inline, inline, jõudlus kasvab aeglaselt – ja siis buum! – see kukub alla nagu kiire tungraud, sest sa vooderdasid liiga palju. Nii toimis kõik enne Java tulekut. Java nõuab palju rohkem inliningut, nii et pidin oma jaoturi palju agressiivsemaks muutma, et see pigem nivelleeriks kui jookseks kokku, ja kui liimida liiga palju, hakkab see laiali valguma, kuid siis tuleb ikkagi hetk "ei enam spilling". See on huvitav tähelepanek ja see tuli mulle lihtsalt eikusagilt, mitte ilmne, kuid see tasus end hästi. Võtsin kasutusele agressiivse inliningi ja see viis mind kohtadesse, kus Java ja C jõudlus töötavad kõrvuti. Need on tõesti lähedased – ma saan kirjutada Java-koodi, mis on oluliselt kiirem kui C-kood ja muud sellised asjad, kuid üldiselt on need asjade suures pildis umbkaudu võrreldavad. Ma arvan, et osa sellest eelisest on registri jagaja, mis võimaldab mul võimalikult rumalalt sisse kirjutada. Ma lihtsalt kirjutan kõike, mida näen. Siin on küsimus selles, kas jaotur töötab hästi, kas tulemuseks on intelligentselt töötav kood. See oli suur väljakutse: sellest kõigest aru saada ja see toimima panna.

Natuke registri eraldamisest ja mitmest tuumast

Vladimir: Sellised probleemid nagu registri eraldamine tunduvad mingi igavese, lõputu teemana. Huvitav, kas kunagi on olnud idee, mis tundus paljulubav ja siis praktikas läbi kukkus?

Kalju: Kindlasti! Registri eraldamine on valdkond, kus proovite leida heuristikat NP-täieliku probleemi lahendamiseks. Ja täiuslikku lahendust ei saa kunagi saavutada, eks? See on lihtsalt võimatu. Vaata, Ahead of Time koostamine – see töötab ka halvasti. Siin räägitakse mõnest keskmisest juhtumist. Tüüpilisest jõudlusest, et saaksite minna ja mõõta midagi, mis on teie arvates hea tüüpiline jõudlus – te ju töötate selle parandamise nimel! Registrite jaotamine on jõudluse teema. Kui teil on esimene prototüüp, see töötab ja värvib vajaliku, algab esinemistöö. Peate õppima hästi mõõtma. Miks see oluline on? Kui teil on selged andmed, võite vaadata erinevaid valdkondi ja näha: jah, see aitas siin, aga seal kõik läks katki! Tekivad mõned head ideed, lisad uue heuristika ja järsku hakkab kõik keskmiselt veidi paremini toimima. Või ei käivitu. Mul oli hunnik juhtumeid, kus me võitlesime viieprotsendilise jõudluse eest, mis eristas meie arengut eelmisest jaoturist. Ja iga kord näeb see välja selline: kuskil võidad, kuskil kaotad. Kui teil on head toimivusanalüüsi tööriistad, saate leida kaotavad ideed ja mõista, miks need ebaõnnestuvad. Võib-olla tasub jätta kõik nii, nagu on, või läheneda peenhäälestamisele tõsisemalt või minna välja ja midagi muud korda teha. See on terve hulk asju! Ma tegin selle laheda häkkimise, aga mul on vaja ka seda, seda ja seda – ja nende kombinatsioon annab mõningaid täiustusi. Ja üksildased võivad ebaõnnestuda. Selline on NP-täielike probleemidega seotud jõudlustöö olemus.

Vladimir: Jääb tunne, et sellised asjad nagu allokaatorites värvimine on probleem, mis on juba lahendatud. Noh, see on teie jaoks otsustatud, otsustades selle järgi, mida te ütlete, nii et kas see on isegi seda väärt...

Kalju: See ei ole sellisena lahendatud. Teie peate selle muutma "lahendatud". On raskeid probleeme ja need tuleb lahendada. Kui see on tehtud, on aeg töötada tootlikkuse kallal. Peate sellele tööle vastavalt lähenema - tegema võrdlusuuringuid, koguma mõõdikuid, selgitama olukordi, kui eelmisele versioonile tagasi pöördudes hakkas teie vana häkkimine uuesti tööle (või vastupidi, peatus). Ja ära anna alla enne, kui oled midagi saavutanud. Nagu ma juba ütlesin, kui on lahedaid ideid, mis ei töötanud, kuid ideeregistrite jaotamise valdkonnas on see ligikaudu lõputu. Saate näiteks lugeda teaduslikke väljaandeid. Kuigi nüüd on see ala hakanud palju aeglasemalt liikuma ja selgemaks saanud kui nooruses. Sellel alal tegutseb aga lugematu hulk inimesi ja kõik nende ideed on proovimist väärt, kõik ootavad tiibadesse. Ja te ei saa aru, kui head need on, kui te neid ei proovi. Kui hästi need teie jaoturis kõige muuga integreeruvad, sest jagaja teeb palju asju ja mõned ideed ei tööta teie konkreetses jaoturis, kuid teises jaoturis saavad need hõlpsasti hakkama. Peamine viis jaoturi jaoks võitmiseks on tõmmata aeglane kraam põhiteest välja ja sundida seda mööda aeglaste radade piire poolitama. Nii et kui soovite käivitada GC-d, vali aeglane tee, deoptimeerige, tehke erand, kõik see värk – teate, et need asjad on suhteliselt haruldased. Ja need on tõesti haruldased, kontrollisin. Teete lisatööd ja see eemaldab nendel aeglastel teedel palju piiranguid, kuid see pole tegelikult oluline, kuna need on aeglased ja neid sõidetakse harva. Näiteks null osuti – seda ei juhtu kunagi, eks? Erinevate asjade jaoks peab teil olema mitu teed, kuid need ei tohiks segada peamist. 

Vladimir: Mida arvate mitmetuumalistest, kui tuumasid on korraga tuhandeid? Kas see on kasulik asi?

Kalju: GPU edu näitab, et see on üsna kasulik!

Vladimir: Nad on üsna spetsialiseerunud. Aga üldotstarbelised töötlejad?

Kalju: No see oli Azuli ärimudel. Vastus tuli tagasi ajastul, mil inimesed tõesti armastasid etteaimatavat jõudlust. Paralleelkoodi oli siis raske kirjutada. H2O kodeerimismudel on väga skaleeritav, kuid see ei ole üldotstarbeline mudel. Võib-olla veidi üldisem kui GPU kasutamisel. Kas me räägime sellise asja arendamise keerukusest või kasutamise keerukusest? Näiteks andis Azul mulle huvitava õppetunni, üsna ebaselge: väikesed vahemälud on normaalsed. 

Suurim väljakutse elus

Vladimir: Aga mittetehnilised väljakutsed?

Kalju: Suurim väljakutse oli mitte olla... lahke ja tore inimeste vastu. Ja sellest tulenevalt sattusin pidevalt äärmiselt konfliktsetesse olukordadesse. Need, kus ma teadsin, et asjad lähevad valesti, kuid ei teadnud, kuidas nende probleemidega edasi liikuda, ega saanud nendega toime. Nii tekkis palju pikaajalisi, aastakümneid kestvaid probleeme. Asjaolu, et Java-l on C1 ja C2 kompilaatorid, on selle otsene tagajärg. Otsene tagajärg on ka see, et kümme aastat järjest ei olnud Javas mitmetasandilist koostamist. On ilmselge, et meil oli sellist süsteemi vaja, kuid pole ilmne, miks seda ei olnud. Mul oli probleeme ühe inseneriga... või inseneride rühmaga. Kunagi, kui ma Sunis tööle hakkasin, olin... Okei, mitte ainult siis, mul on üldiselt alati kõige kohta oma arvamus. Ja ma arvasin, et see on tõsi, et võite lihtsalt võtta selle oma tõe ja rääkida sellest otse välja. Seda enam, et mul oli enamuse ajast šokeerivalt õigus. Ja kui sulle see lähenemine ei meeldi... eriti kui sa ilmselgelt eksid ja teed lollusi... Üldiselt suudavad vähesed inimesed seda suhtlusvormi taluda. Kuigi mõned võiksid, nagu mina. Olen kogu oma elu ehitanud meritokraatlikele põhimõtetele. Kui näitad mulle midagi valesti, keeran kohe ümber ja ütlen: sa ütlesid lolli juttu. Samas ma muidugi vabandan ja kõik muu, märgin ära eelised, kui neid on, ja võtan kasutusele muud õiged toimingud. Teisest küljest on mul šokeerivalt õigus šokeerivalt suure protsendi osas kogu ajast. Ja see ei tööta inimestega suhetes eriti hästi. Ma ei ürita olla kena, vaid esitan küsimuse otse. "See ei tööta kunagi, sest üks, kaks ja kolm." Ja nad ütlesid: "Oh!" Oli ka teisi tagajärgi, mida oli ilmselt parem ignoreerida: näiteks need, mis viisid mu naisest lahutuse ja pärast seda kümme aastat depressioonini.

Väljakutse on võitlus inimestega, nende arusaamaga sellest, mida saate või ei saa teha, mis on oluline ja mis mitte. Kodeerimisstiiliga seoses oli palju väljakutseid. Kirjutan endiselt palju koodi ja neil päevil pidin isegi hoogu maha võtma, kuna tegin liiga palju paralleelseid ülesandeid ja tegin neid halvasti, selle asemel et ühele keskenduda. Tagantjärele mõeldes kirjutasin poole koodist Java JIT käsule, käsule C2. Järgmine kiireim kodeerija kirjutas poole aeglasemalt, järgmine poole aeglasemalt ja see oli eksponentsiaalne langus. Seitsmes inimene selles reas oli väga-väga aeglane – seda juhtub alati! Puudutasin palju koodi. Vaatasin, kes mida kirjutas, eranditult vahtisin nende koodi, vaatasin kõik üle ja kirjutasin ikka rohkem ise kui ükski neist. See lähenemisviis ei tööta inimestega eriti hästi. Mõnele inimesele see ei meeldi. Ja kui nad sellega hakkama ei saa, algavad igasugused kaebused. Näiteks öeldi mulle kord, et lõpetage kodeerimine, kuna kirjutasin liiga palju koodi ja see seab meeskonna ohtu ning see kõik kõlas minu jaoks naljana: kutt, kui ülejäänud meeskond kaob ja ma jätkan koodi kirjutamist, siis sina Kaotan ainult pooled meeskonnad. Teisest küljest, kui ma jätkan koodi kirjutamist ja te kaotate poole meeskonnast, kõlab see väga halva juhtimisena. Ma ei mõelnud sellele kunagi, ei rääkinud sellest kunagi, aga see oli ikkagi kuskil mu peas. Mu peas keerles mõte: "Kas te teete minuga nalja?" Seega oli suurim probleem mina ja minu suhted inimestega. Nüüd mõistan ennast palju paremini, olin pikka aega programmeerijate meeskonnajuht ja nüüd ütlen inimestele otse: teate, ma olen see, kes ma olen ja te peate minuga tegelema - kas see on okei, kui ma seisan siin? Ja kui nad sellega tegelema hakkasid, siis kõik toimis. Tegelikult pole ma ei halb ega hea, mul pole halbu kavatsusi ega isekaid püüdlusi, see on lihtsalt minu olemus ja ma pean sellega kuidagi elama.

Andrew: Alles hiljuti hakkasid kõik rääkima introvertide eneseteadvusest ja pehmetest oskustest üldiselt. Mida selle kohta öelda?

Kalju: Jah, see oli arusaam ja õppetund, mille sain oma naisest lahutamisest. Mida ma lahutusest õppisin, oli iseenda mõistmine. Nii hakkasin mõistma teisi inimesi. Saate aru, kuidas see suhtlus toimib. See viis üksteise järel avastusteni. Tekkis teadlikkus sellest, kes ma olen ja mida ma esindan. Mida ma teen: kas olen ülesandega hõivatud või väldin konflikte või midagi muud – ja see eneseteadlikkuse tase aitab tõesti ennast kontrolli all hoida. Pärast seda läheb kõik palju lihtsamaks. Üks asi, mida ma avastasin mitte ainult enda, vaid ka teiste programmeerijate puhul, on võimetus mõtteid verbaliseerida, kui olete emotsionaalse stressi seisundis. Näiteks istud seal kodeerides, voolavas olekus ja siis nad jooksevad sinu juurde ja hakkavad hüsteeriliselt karjuma, et midagi on katki ja nüüd võetakse sinu vastu äärmuslikke meetmeid. Ja te ei saa sõnagi öelda, sest olete emotsionaalses stressis. Omandatud teadmised võimaldavad selleks hetkeks valmistuda, see üle elada ja liikuda edasi taganemisplaanile, mille järel saab midagi ette võtta. Nii et jah, kui hakkate mõistma, kuidas see kõik töötab, on see tohutu elumuutev sündmus. 
Ma ise ei leidnud õigeid sõnu, aga tegevuste jada jäi meelde. Asi on selles, et see reaktsioon on nii füüsiline kui ka verbaalne ja teil on vaja ruumi. Selline ruum zeni mõttes. Just seda tulebki selgitada ja siis kohe kõrvale astuda – puhtfüüsiliselt eemale. Kui ma verbaalselt vaikin, suudan olukorda emotsionaalselt töödelda. Kui adrenaliin jõuab teie ajju, lülitab teid võitlus- või lennurežiimile, ei saa te enam midagi öelda, ei - nüüd olete idioot, piitsutav insener, kes ei suuda korralikult reageerida ega isegi rünnakut peatada ja ründaja on vaba. ikka ja jälle rünnata. Kõigepealt peate uuesti saama iseendaks, taastama kontrolli, väljuma režiimist "võitle või põgene".

Ja selleks vajame verbaalset ruumi. Lihtsalt vaba ruumi. Kui te üldse midagi ütlete, siis võite täpselt seda öelda ja siis minna ja leida endale tõesti “ruum”: minge parki jalutama, lukustage end duši alla - see pole oluline. Peaasi on ajutiselt sellest olukorrast lahti ühendada. Niipea, kui vähemalt mõneks sekundiks välja lülitate, taastub kontroll, hakkate kainelt mõtlema. "Olgu, ma ei ole mingi idioot, ma ei tee rumalusi, ma olen üsna kasulik inimene." Kui olete suutnud end veenda, on aeg liikuda järgmise etapi juurde: juhtunu mõistmisele. Sind rünnati, rünnak tuli sealt, kust sa seda ei oodanud, see oli ebaaus, alatu varitsus. See on halb. Järgmine samm on mõista, miks ründajal seda vaja oli. Tõesti, miks? Võib-olla sellepärast, et ta ise on maruvihane? Miks ta vihane on? Näiteks sellepärast, et ta keeras end ise üles ega suuda vastutust võtta? See on viis, kuidas kogu olukorda hoolikalt käsitleda. Kuid see nõuab manööverdamisruumi, verbaalset ruumi. Esimene samm on verbaalse kontakti katkestamine. Vältige sõnadega arutelu. Tühistage see, kõndige nii kiiresti kui võimalik. Kui see on telefonivestlus, siis lihtsalt katkestage toru – see on oskus, mille õppisin oma endise naisega suheldes. Kui vestlus ei edene, öelge lihtsalt "hüvasti" ja katkestage kõne. Teiselt poolt telefoni: "blaa bla bla", vastate: "jah, nägemist!" ja pange toru ära. Sa lihtsalt lõpetad vestluse. Viis minutit hiljem, kui mõistliku mõtlemise oskus naaseb, oled veidi jahtunud, saab võimalikuks mõelda kõigele, juhtunule ja edasisele. Ja alustage läbimõeldud vastuse sõnastamist, selle asemel, et reageerida lihtsalt emotsioonidest lähtuvalt. Minu jaoks oli eneseteadvuse läbimurre just see, et emotsionaalse stressi korral ei saa ma rääkida. Sellest seisundist väljatulek, mõtlemine ja planeerimine, kuidas probleemidele reageerida ja kompenseerida – need on õiged sammud juhuks, kui sa ei saa rääkida. Lihtsaim viis on põgeneda olukorrast, kus emotsionaalne stress avaldub, ja lihtsalt lõpetada selles stressis osalemine. Pärast seda muutud mõtlemisvõimeliseks, kui suudad mõelda, muutud võimeliseks rääkima jne.

Muide, kohtus üritab vastaspoolne advokaat seda teiega teha - nüüd on selge, miks. Sest tal on võime sind nii alla suruda, et sa ei suuda näiteks isegi oma nime välja öelda. Väga reaalses mõttes sa ei saa rääkida. Kui see juhtub teiega ja teate, et leiate end kohast, kus käib verbaalne võitlus, näiteks kohus, siis võite tulla koos oma advokaadiga. Advokaat seisab teie eest ja peatab verbaalse rünnaku ning teeb seda täiesti seaduslikul viisil ning kaotatud Zeni ruum naaseb teie juurde. Näiteks pidin paar korda perele helistama, kohtunik oli selles osas üsna sõbralik, kuid vastasseisu advokaat karjus ja karjus minu peale, ma ei saanud isegi sõna sekka. Nendel juhtudel sobib mulle kõige paremini vahendaja kasutamine. Vahendaja peatab kogu selle surve, mis sulle pideva vooluna peale valgub, leiad vajaliku Zen-ruumi ja koos sellega naaseb ka kõnevõime. See on terve teadmiste valdkond, milles on palju uurida, palju enda sees avastada ja see kõik kujuneb kõrgetasemelisteks strateegilisteks otsusteks, mis on erinevate inimeste jaoks erinevad. Mõnel inimesel ülalkirjeldatud probleeme ei ole, tavaliselt professionaalsetel müügiinimestel neid ei ole. Kõik need inimesed, kes elatuvad sõnadega – kuulsad lauljad, luuletajad, usujuhid ja poliitikud, neil on alati midagi öelda. Neil pole selliseid probleeme, aga minul on.

Andrew: See oli... ootamatu. Suurepärane, oleme juba palju rääkinud ja on aeg see intervjuu lõpetada. Kindlasti kohtume konverentsil ja saame seda dialoogi jätkata. Kohtumiseni Hydras!

Vestlust Cliffiga saate jätkata konverentsil Hydra 2019, mis toimub 11.-12 Peterburis. Ta tuleb aruandega "Azuli riistvara tehingumälu kogemus". Pileteid saab osta ametlikul veebisaidil.

Allikas: www.habr.com

Lisa kommentaar