Sjajan intervju s Cliffom Clickom, ocem JIT kompilacije u Javi

Sjajan intervju s Cliffom Clickom, ocem JIT kompilacije u JaviCliff Click — CTO tvrtke Cratus (IoT senzori za poboljšanje procesa), osnivač i suosnivač nekoliko startupa (uključujući Rocket Realtime School, Neurensic i H2O.ai) s nekoliko uspješnih izlazaka. Cliff je napisao svoj prvi prevodilac sa 15 godina (Pascal za TRS Z-80)! Najpoznatiji je po svom radu na C2 u Javi (The Sea of ​​​​Nodes IR). Ovaj kompajler pokazao je svijetu da JIT može proizvoditi visokokvalitetni kod, što je bio jedan od čimbenika u pojavi Jave kao jedne od glavnih modernih softverskih platformi. Zatim je Cliff pomogao tvrtki Azul Systems izgraditi glavno računalo s 864 jezgre s čistim Java softverom koji je podržavao GC pauze na gomili od 500 gigabajta unutar 10 milisekundi. Općenito, Cliff je uspio raditi na svim aspektima JVM-a.

 
Ovaj habrapost je sjajan intervju s Cliffom. Razgovarat ćemo o sljedećim temama:

  • Prijelaz na optimizacije niske razine
  • Kako napraviti veliki refactoring
  • Troškovni model
  • Trening optimizacije niske razine
  • Praktični primjeri poboljšanja performansi
  • Zašto kreirati vlastiti programski jezik
  • Karijera inženjera izvedbe
  • Tehnički izazovi
  • Malo o dodjeli registara i više jezgri
  • Najveći izazov u životu

Razgovore vode:

  • Andrej Satarin iz Amazon Web Services. U svojoj karijeri uspio je raditi na potpuno različitim projektima: testirao je distribuiranu bazu podataka NewSQL u Yandexu, sustav detekcije oblaka u Kaspersky Labu, igricu za više igrača u Mail.ru i servis za izračun cijena deviza u Deutsche Bank. Zanima me testiranje velikih pozadinskih i distribuiranih sustava.
  • Vladimir Sitnikov iz Netcrackera. Deset godina rada na performansama i skalabilnosti NetCracker OS-a, softvera koji telekom operateri koriste za automatizaciju procesa upravljanja mrežom i mrežnom opremom. Zanimaju me problemi s performansama Java i Oracle baze podataka. Autor više od desetak poboljšanja performansi u službenom PostgreSQL JDBC upravljačkom programu.

Prijelaz na optimizacije niske razine

Andrija: Vi ste veliko ime u svijetu JIT kompilacije, Jave i izvedbenog rada općenito, zar ne? 

Litica: Tako je!

Andrija: Počnimo s nekim općim pitanjima o izvedbenom radu. Što mislite o izboru između optimizacije visoke i niske razine kao što je rad na razini procesora?

Litica: Da, ovdje je sve jednostavno. Najbrži kod je onaj koji se nikada ne pokreće. Stoga uvijek treba krenuti od visoke razine, raditi na algoritmima. Bolji O zapis će pobijediti lošiji O zapis osim ako se ne umiješaju neke dovoljno velike konstante. Niske stvari idu na kraju. U pravilu, ako ste dovoljno dobro optimizirali ostatak svoje gomile i još uvijek je ostalo nešto zanimljivih stvari, to je niska razina. Ali kako krenuti s visoke razine? Kako znate da je obavljeno dovoljno posla na visokoj razini? Pa... nema šanse. Nema gotovih recepata. Morate razumjeti problem, odlučiti što ćete učiniti (kako ne biste poduzimali nepotrebne korake u budućnosti) i onda možete otkriti profiler, koji može reći nešto korisno. U nekom trenutku i sami shvatite da ste se riješili nepotrebnih stvari i da je vrijeme za fino podešavanje niske razine. Ovo je svakako posebna vrsta umjetnosti. Mnogo je ljudi koji rade nepotrebne stvari, ali se kreću toliko brzo da nemaju vremena brinuti o produktivnosti. Ali to je sve dok se pitanje otvoreno ne pojavi. Obično 99% vremena nikoga nije briga što ja radim, sve do trenutka kada se na kritičnom putu pojavi važna stvar koja nikoga ne zanima. I tu vam svi počnu prigovarati "zašto nije savršeno funkcioniralo od samog početka". Općenito, uvijek postoji nešto za poboljšanje performansi. Ali 99% vremena nemate potencijalnih kupaca! Samo pokušavate učiniti da nešto funkcionira i u tom procesu shvaćate što je važno. Nikada ne možete unaprijed znati da ovaj komad mora biti savršen, tako da, zapravo, morate biti savršeni u svemu. Ali to je nemoguće i vi to ne radite. Uvijek ima puno stvari za popraviti – i to je sasvim normalno.

Kako napraviti veliki refactoring

Andrija: Kako radite na nastupu? Ovo je međusektorski problem. Na primjer, jeste li ikada morali raditi na problemima koji proizlaze iz presjeka velikog broja postojećih funkcionalnosti?

Litica: Pokušavam to izbjeći. Ako znam da će izvedba biti problem, razmislim o tome prije nego što počnem kodirati, posebno s podatkovnim strukturama. Ali često sve to otkrijete vrlo kasnije. A onda morate ići na krajnje mjere i učiniti ono što ja zovem "prepisati i osvojiti": trebate zgrabiti dovoljno velik komad. Dio koda ipak će morati biti ponovno napisan zbog problema s performansama ili nečeg drugog. Bez obzira na razlog za ponovno pisanje koda, gotovo je uvijek bolje ponovno napisati veći nego manji dio. U tom trenutku svi se počnu tresti od straha: "o moj Bože, ne možete dirati toliko koda!" Ali zapravo, ovaj pristup gotovo uvijek djeluje mnogo bolje. Trebate odmah prihvatiti veliki problem, nacrtati veliki krug oko njega i reći: Ja ću prepisati sve unutar kruga. Rub je puno manji od sadržaja unutar njega koji treba zamijeniti. A ako vam takvo iscrtavanje granica omogućuje savršeno obavljanje posla iznutra, ruke su vam slobodne, radite što želite. Jednom kada shvatite problem, proces prepisivanja je mnogo lakši, stoga zagrizite veliki zalogaj!
U isto vrijeme, kada napravite veliku prepravku i shvatite da će izvedba biti problem, možete se odmah početi brinuti o tome. To se obično pretvori u jednostavne stvari poput "nemojte kopirati podatke, upravljajte podacima što je jednostavnije moguće, smanjite ih." U velikim prepisivanjima postoje standardni načini poboljšanja performansi. I gotovo se uvijek vrte oko podataka.

Troškovni model

Andrija: U jednom od podcasta govorili ste o troškovnim modelima u kontekstu produktivnosti. Možete li objasniti što ste time mislili?

Litica: Sigurno. Rođen sam u doba kada su performanse procesora bile izuzetno važne. I ovo se doba ponovno vraća - sudbina nije bez ironije. Počeo sam živjeti u danima osmobitnih strojeva; moje prvo računalo radilo je s 256 bajtova. Točno bajtova. Sve je bilo jako malo. Upute su se morale prebrojati, a kako smo se kretali prema gore na hrpi programskih jezika, jezici su preuzimali sve više i više. Postojao je Asembler, zatim Basic, pa C, a C se pobrinuo za mnoge detalje, poput dodjele registara i odabira instrukcija. Ali tamo je sve bilo sasvim jasno, i ako bih napravio pokazivač na instancu varijable, tada bih dobio opterećenje, a cijena ove instrukcije je poznata. Hardver proizvodi određeni broj strojnih ciklusa, tako da se brzina izvršenja različitih stvari može izračunati jednostavnim zbrajanjem svih instrukcija koje ćete pokrenuti. Svaka usporedba/testiranje/grana/poziv/učitavanje/pohrana može se zbrojiti i reći: to je vrijeme izvršenja za vas. Kada radite na poboljšanju performansi, svakako ćete obratiti pozornost na to koji brojevi odgovaraju malim vrućim ciklusima. 
Ali čim prijeđete na Javu, Python i slične stvari, vrlo brzo se odmaknete od low-level hardvera. Kolika je cijena pozivanja gettera u Javi? Ako je JIT u HotSpotu ispravan umetnuti, učitati će se, ali ako to nije učinio, bit će to poziv funkcije. Budući da je poziv u vrućoj petlji, on će nadjačati sve druge optimizacije u toj petlji. Stoga će stvarni trošak biti puno veći. I odmah gubite mogućnost da pogledate dio koda i shvatite da bismo ga trebali izvršiti u smislu brzine takta procesora, korištene memorije i predmemorije. Sve to postaje zanimljivo samo ako se stvarno upustite u izvedbu.
Sada smo se našli u situaciji u kojoj se brzine procesora gotovo da i nisu povećale već desetljeće. Vraćaju se stari dani! Više ne možete računati na dobre performanse jedne niti. Ali ako odjednom uđete u paralelno računanje, to je nevjerojatno teško, svi vas gledaju kao Jamesa Bonda. Desetostruka ubrzanja ovdje se obično javljaju na mjestima gdje je netko nešto zabrljao. Konkurentnost zahtijeva puno rada. Da biste dobili to XNUMXx ubrzanje, morate razumjeti troškovni model. Što i koliko košta? A da biste to učinili, morate razumjeti kako jezik pristaje na hardver ispod.
Martin Thompson odabrao je sjajnu riječ za svoj blog Mehanička simpatija! Morate razumjeti što će hardver učiniti, kako će točno to učiniti i zašto uopće radi to što radi. Koristeći ovo, prilično je lako početi brojati instrukcije i odgonetnuti kamo ide vrijeme izvršenja. Ako nemate odgovarajuću obuku, samo tražite crnu mačku u mračnoj sobi. Vidim ljude kako cijelo vrijeme optimiziraju izvedbu, a nemaju pojma što dovraga rade. Mnogo pate i ne napreduju puno. A kad uzmem isti dio koda, ubacim nekoliko malih hakiranja i dobijem peterostruko ili deseterostruko ubrzanje, oni kažu: pa, to nije pošteno, već smo znali da si bolji. Nevjerojatno. O čemu ja pričam... troškovni model je o tome kakvu vrstu koda pišete i koliko brzo radi u prosjeku u velikoj slici.

Andrija: A kako možeš držati toliki volumen u glavi? Da li se to postiže s više iskustva ili? Odakle takvo iskustvo?

Litica: Pa, nisam na najlakši način stekao svoje iskustvo. Programirao sam u skupštini u danima kada ste mogli razumjeti svaku instrukciju. Zvuči glupo, ali od tada je Z80 set instrukcija uvijek ostao u mojoj glavi, u mom sjećanju. Ne sjećam se imena ljudi u minuti razgovora, ali sjećam se koda napisanog prije 40 godina. Smiješno je, izgleda kao sindrom"idiot znanstvenik".

Trening optimizacije niske razine

Andrija: Postoji li lakši način za ulazak?

Litica: Da i ne. Hardver koji svi koristimo nije se previše promijenio tijekom vremena. Svi koriste x86, osim Armovih pametnih telefona. Ako ne radite neku vrstu hardcore ugradnje, radite istu stvar. U redu, sljedeći. Upute se također nisu mijenjale stoljećima. Trebate otići nešto napisati u Skupštinu. Ne puno, ali dovoljno da počnete razumjeti. Smiješ se, ali ja govorim potpuno ozbiljno. Morate razumjeti korespondenciju između jezika i hardvera. Nakon toga morate malo pisati i napraviti mali kompilator za mali jezik igračaka. Nalik na igračku znači da se mora izraditi u razumnom roku. Može biti super jednostavno, ali mora generirati upute. Čin generiranja instrukcija pomoći će vam da razumijete troškovni model za most između koda visoke razine koji svi pišu i strojnog koda koji se izvodi na hardveru. Ova korespondencija će biti spaljena u mozak u vrijeme kada kompilator bude pisan. Čak i najjednostavniji kompilator. Nakon toga možete početi promatrati Javu i činjenicu da je njezina semantička provalija puno dublja, te je puno teže graditi mostove preko nje. U Javi je puno teže razumjeti je li naš most ispao dobar ili loš, zbog čega će se raspasti, a zbog čega neće. Ali potrebna vam je neka vrsta polazišta gdje ćete pogledati kod i razumjeti: "da, ovaj getter bi trebao biti ugrađen svaki put." I onda se ispostavi da se to ponekad dogodi, osim u situaciji kada metoda postane prevelika, a JIT počne sve inlinerati. Učinkovitost takvih mjesta može se predvidjeti trenutno. Obično getteri rade dobro, ali onda pogledate velike vruće petlje i shvatite da tamo lebde neki pozivi funkcija koji ne znaju što rade. Ovo je problem sa širokom upotrebom gettera, razlog zašto nisu ugrađeni je taj što nije jasno jesu li getteri. Ako imate super malu bazu koda, možete je jednostavno zapamtiti i onda reći: ovo je getter, a ovo je setter. U velikoj bazi koda, svaka funkcija živi svoju povijest, koja, općenito, nikome nije poznata. Profiler kaže da smo izgubili 24% vremena na nekoj petlji i da bismo razumjeli što ta petlja radi, moramo pogledati svaku funkciju unutra. To je nemoguće razumjeti bez proučavanja funkcije, a to ozbiljno usporava proces razumijevanja. Zato ne koristim getere i postavljače, došao sam na novu razinu!
Gdje nabaviti troškovni model? Pa, možete nešto pročitati, naravno... Ali mislim da je najbolje djelovati. Izrada malog kompajlera bit će najbolji način da shvatite troškovni model i uklopite ga u vlastitu glavu. Mali kompajler koji bi bio prikladan za programiranje mikrovalne pećnice zadatak je za početnika. Pa, mislim, ako već imate vještine programiranja, onda bi to trebalo biti dovoljno. Sve ove stvari kao što je raščlanjivanje niza koji imate kao neku vrstu algebarskog izraza, izvlačenje uputa za matematičke operacije odatle ispravnim redoslijedom, uzimanje točnih vrijednosti iz registara - sve se to radi odjednom. I dok to radite, to će vam se utisnuti u mozak. Mislim da svi znaju što kompilator radi. A to će dati razumijevanje modela troška.

Praktični primjeri poboljšanja performansi

Andrija: Na što još treba obratiti pozornost kada radite na produktivnosti?

Litica: Strukture podataka. Usput, da, dugo nisam držao ove tečajeve... Raketna škola. Bilo je zabavno, ali iziskivalo je puno truda, a ja imam i život! U REDU. Dakle, u jednom od velikih i zanimljivih predavanja, "Kamo ide tvoj učinak", dao sam studentima primjer: dva i pol gigabajta fintech podataka pročitano je iz CSV datoteke i onda su morali izračunati broj prodanih proizvoda . Redoviti podaci o tržištu. UDP paketi pretvoreni u tekstualni format od 70-ih. Chicago Mercantile Exchange - svakakve stvari poput maslaca, kukuruza, soje i sličnih stvari. Bilo je potrebno prebrojati te proizvode, broj transakcija, prosječni obujam kretanja sredstava i robe itd. To je prilično jednostavna trgovačka matematika: pronađite šifru proizvoda (to je 1-2 znaka u hash tablici), uzmite iznos, dodajte ga u jedan od trgovinskih skupova, dodajte volumen, dodajte vrijednost i još nekoliko stvari. Vrlo jednostavna matematika. Implementacija igračke bila je vrlo jednostavna: sve je u datoteci, čitam datoteku i krećem se kroz nju, dijeleći pojedinačne zapise u Java nizove, tražeći potrebne stvari u njima i zbrajajući ih prema gore opisanoj matematici. I radi na nekoj maloj brzini.

Uz ovaj pristup, očito je što se događa, a paralelno računanje neće pomoći, zar ne? Ispada da se peterostruko povećanje performansi može postići jednostavnim odabirom pravih struktura podataka. I to iznenađuje čak i iskusne programere! U mom konkretnom slučaju, trik je bio u tome da ne biste trebali vršiti dodjelu memorije u vrućoj petlji. Pa, ovo nije cijela istina, ali općenito - ne biste trebali istaknuti "jednom u X" kada je X dovoljno velik. Kada je X dva i pol gigabajta, ne biste trebali dodijeliti ništa “jednom po slovu”, ili “jednom po retku”, ili “jednom po polju”, ništa slično. Ovdje se troši vrijeme. Kako ovo uopće funkcionira? Zamislite da ja zovem String.split() ili BufferedReader.readLine(). Readline čini niz od skupa bajtova koji dolaze preko mreže, jednom za svaku liniju, za svaku od stotina milijuna linija. Uzimam ovaj redak, analiziram ga i bacam. Zašto ga bacam - dobro, već sam ga obradio, to je sve. Dakle, za svaki bajt pročitan iz ovih 2.7G, dva znaka će biti napisana u retku, dakle već 5.4G, i ne trebaju mi ​​za ništa dalje, pa se bacaju. Ako pogledate propusnost memorije, učitavamo 2.7G koji prolazi kroz memoriju i memorijsku sabirnicu u procesoru, a onda se dvostruko više šalje na liniju koja leži u memoriji, a sve se to pohaba kad se kreira svaka nova linija. Ali trebam ga pročitati, hardver to čita, čak i ako se kasnije sve pohaba. I moram to zapisati jer sam napravio redak i predmemorije su pune - predmemorija ne može primiti 2.7G. Dakle, za svaki bajt koji pročitam, pročitam još dva bajta i napišem još dva bajta, i na kraju imaju omjer 4:1 - u ovom omjeru gubimo propusnost memorije. I onda se ispostavi da ako to učinim String.split() – ovo nije zadnji put da ovo radim, možda ima još 6-7 polja unutra. Dakle, klasični kod čitanja CSV-a i potom analiziranja nizova rezultira gubitkom propusnosti memorije od oko 14:1 u odnosu na ono što biste zapravo željeli imati. Ako odbacite ove odabire, možete dobiti peterostruko ubrzanje.

I nije tako teško. Ako pogledate kod iz pravog kuta, sve postaje vrlo jednostavno kada shvatite problem. Ne biste trebali potpuno prestati dodjeljivati ​​memoriju: jedini je problem što nešto dodijelite i ono odmah umre, a usput spali važan resurs, a to je u ovom slučaju propusnost memorije. A sve to rezultira padom produktivnosti. Na x86 obično morate aktivno snimati cikluse procesora, ali ovdje ste potrošili svu memoriju mnogo ranije. Rješenje je smanjiti količinu iscjetka. 
Drugi dio problema je taj da ako pokrenete profiler kad ponestane memorijske trake, baš kad se to dogodi, obično čekate da se predmemorija vrati jer je puna smeća koje ste upravo proizveli, svih tih redaka. Stoga svaka operacija učitavanja ili pohranjivanja postaje spora, jer dovode do promašaja predmemorije - cijela predmemorija je postala spora, čekajući da je smeće napusti. Stoga će profiler samo prikazati topli nasumični šum razmazan kroz cijelu petlju - neće biti posebne vruće upute ili mjesta u kodu. Samo buka. A ako pogledate GC cikluse, svi su oni mlade generacije i superbrzi - mikrosekunde ili milisekunde maksimalno. Uostalom, sve ovo sjećanje trenutno umire. Vi dodijelite milijarde gigabajta, a on ih reže, i reže, i opet reže. Sve se to događa vrlo brzo. Ispostavilo se da postoje jeftini GC ciklusi, topli šum duž cijelog ciklusa, ali mi želimo dobiti 5x ubrzanje. U ovom trenutku nešto bi se trebalo zatvoriti u vašoj glavi i zvučati: "zašto je ovo?!" Prelijevanje trake memorije ne prikazuje se u klasičnom programu za ispravljanje pogrešaka; morate pokrenuti program za ispravljanje pogrešaka brojača izvedbe hardvera i vidjeti ga sami i izravno. Ali to se ne može izravno posumnjati iz ova tri simptoma. Treći simptom je kada pogledate što ističete, pitate profilera, a on vam odgovori: "Napravili ste milijardu redaka, ali GC je radio besplatno." Čim se to dogodi, shvatite da ste stvorili previše objekata i spalili cijelu stazu sjećanja. Postoji način da se to shvati, ali nije očit. 

Problem je u strukturi podataka: gola struktura na kojoj se nalazi sve što se događa, prevelika je, ima 2.7 G na disku, pa je pravljenje kopije ove stvari vrlo nepoželjno - želite je odmah učitati iz mrežnog međuspremnika bajtova u registre, kako ne bi čitali-pisali u red naprijed-natrag pet puta. Nažalost, Java vam ne daje takvu biblioteku kao dio JDK-a prema zadanim postavkama. Ali ovo je trivijalno, zar ne? U biti, ovo je 5-10 redaka koda koji će se koristiti za implementaciju vašeg vlastitog učitavača nizova u međuspremniku, koji ponavlja ponašanje klase nizova, dok je omotač temeljnog međuspremnika bajtova. Kao rezultat toga, ispada da radite gotovo kao s nizovima, ali zapravo se pokazivači na međuspremnik tamo pomiču, a neobrađeni bajtovi se nigdje ne kopiraju, te se stoga isti međuspremnici uvijek iznova koriste, i operativni sustav rado preuzima na sebe stvari za koje je dizajniran, poput skrivenog dvostrukog međuspremnika ovih međuspremnika bajtova, a vi više ne prolazite kroz beskrajni tok nepotrebnih podataka. Usput, razumiješ li da je pri radu s GC-om zajamčeno da svaka dodjela memorije neće biti vidljiva procesoru nakon posljednjeg GC ciklusa? Dakle, sve to nikako ne može biti u cacheu, a onda dolazi do 100% garantiranog promašaja. Kada radite s pokazivačem, na x86, oduzimanje registra iz memorije traje 1-2 takta, a čim se to dogodi, plaćate, plaćate, plaćate, jer memorija je sva uključena DEVET cacheva – a ovo je trošak dodjele memorije. Prava vrijednost.

Drugim riječima, strukture podataka najteže je promijeniti. A kada shvatite da ste odabrali pogrešnu strukturu podataka koja će kasnije ubiti izvedbu, obično treba obaviti puno posla, ali ako to ne učinite, stvari će se pogoršati. Prije svega, morate razmisliti o strukturama podataka, to je važno. Glavni trošak ovdje pada na masne podatkovne strukture, koje se počinju koristiti u stilu "Kopirao sam podatkovnu strukturu X u podatkovnu strukturu Y jer mi se više sviđa oblik Y." Ali operacija kopiranja (koja se čini jeftinom) zapravo gubi propusnost memorije i tu je zakopano sve izgubljeno vrijeme izvršenja. Ako imam golemi niz JSON-a i želim ga pretvoriti u strukturirano DOM stablo POJO-a ili tako nešto, operacija raščlanjivanja tog niza i izgradnje POJO-a, a potom ponovno pristupanje POJO-u kasnije, rezultirat će nepotrebnim troškovima - to je nije jeftin. Osim ako trčite oko POJO-a mnogo češće nego oko žice. Umjesto toga, možete pokušati dešifrirati niz i iz njega izdvojiti samo ono što vam je potrebno, bez pretvaranja u bilo kakav POJO. Ako se sve ovo događa na stazi s koje se zahtijeva maksimalna izvedba, nema POJO za vas, morate nekako izravno zakopati liniju.

Zašto kreirati vlastiti programski jezik

Andrija: Rekli ste da, kako biste razumjeli troškovni model, morate pisati vlastiti jezik...

Litica: Nije jezik, već prevodilac. Jezik i prevodilac dvije su različite stvari. Najvažnija razlika je u vašoj glavi. 

Andrija: Usput, koliko ja znam, eksperimentirate sa stvaranjem vlastitih jezika. Za što?

Litica: Zato što mogu! Napola sam u mirovini, pa mi je ovo hobi. Implementirao sam tuđe jezike cijeli život. Također sam dosta radio na svom stilu kodiranja. I zato što vidim probleme u drugim jezicima. Vidim da postoje bolji načini za obavljanje poznatih stvari. I koristio bih ih. Samo sam umoran od gledanja problema u sebi, u Javi, u Pythonu, u bilo kojem drugom jeziku. Sada pišem u React Native, JavaScript i Elm kao hobi koji se ne odnosi na mirovinu, već na aktivan rad. Također pišem na Pythonu i najvjerojatnije ću nastaviti raditi na strojnom učenju za Java pozadine. Postoji mnogo popularnih jezika i svi imaju zanimljive značajke. Svatko je dobar na svoj način i možete pokušati spojiti sve te značajke. Dakle, proučavam stvari koje me zanimaju, ponašanje jezika, pokušavajući doći do razumne semantike. I za sada mi uspijeva! Trenutačno se mučim sa semantikom memorije, jer želim imati kao u C-u i Javi, i dobiti jak model memorije i semantiku memorije za učitavanja i pohrane. U isto vrijeme, imate automatsko zaključivanje tipa kao u Haskell-u. Ovdje pokušavam pomiješati zaključivanje tipa nalik na Haskell s radom memorije u C-u i Javi. To je ono što ja radim zadnjih 2-3 mjeseca npr.

Andrija: Ako izgradite jezik koji preuzima bolje aspekte iz drugih jezika, mislite li da će netko učiniti suprotno: uzeti vaše ideje i koristiti ih?

Litica: Upravo se tako pojavljuju novi jezici! Zašto je Java slična C-u? Budući da je C imao dobru sintaksu koju su svi razumjeli i Java je bila inspirirana ovom sintaksom, dodajući sigurnost tipa, provjeru granica polja, GC, a također su poboljšali neke stvari iz C-a. Dodali su svoje. Ali bili su dosta inspirirani, zar ne? Svatko stoji na ramenima divova koji su došli prije vas – tako se napreduje.

Andrija: Koliko sam shvatio, vaš će jezik biti siguran za pamćenje. Jeste li razmišljali o implementaciji nečega poput provjere posudbe iz Rusta? Jeste li ga pogledali, što mislite o njemu?

Litica: Pa, godinama pišem C, sa svim tim malloc i free, i ručno upravljam životnim vijekom. Znate, 90-95% ručno kontroliranog životnog vijeka ima istu strukturu. I vrlo je, vrlo bolno to raditi ručno. Volio bih da vam kompilator jednostavno kaže što se tamo događa i što ste postigli svojim djelovanjem. Za neke stvari, Borrow Checker to radi odmah. I trebao bi automatski prikazati informacije, razumjeti sve, a ne čak me opterećivati ​​predstavljanjem ovog razumijevanja. Mora napraviti barem lokalnu analizu izbjegavanja, a samo ako ne uspije, tada treba dodati bilješke tipa koje će opisati životni vijek - a takva shema je mnogo složenija od provjere posuđivanja ili bilo koje postojeće provjere memorije. Izbor između "sve je u redu" i "ništa ne razumijem" - ne, mora postojati nešto bolje. 
Dakle, kao netko tko je napisao puno koda u C-u, mislim da je podrška za automatsku kontrolu trajanja najvažnija stvar. Također mi je dosta toga koliko Java koristi memorije, a glavna zamjerka je GC. Kada dodijelite memoriju u Javi, nećete dobiti natrag memoriju koja je bila lokalna u zadnjem GC ciklusu. To nije slučaj u jezicima s preciznijim upravljanjem memorijom. Ako pozovete malloc, odmah dobivate memoriju koja je obično upravo korištena. Obično radite neke privremene stvari s memorijom i odmah je vraćate natrag. I odmah se vraća u malloc bazen, a sljedeći malloc ciklus ga ponovno izvlači. Stoga je stvarna upotreba memorije svedena na skup živih objekata u određenom trenutku, plus curenja. I ako sve ne iscuri na sasvim nepristojan način, većina memorije završi u cache-u i procesoru, a radi brzo. Ali zahtijeva puno ručnog upravljanja memorijom s malloc i free pozvanim pravim redoslijedom, na pravom mjestu. Rust to može sam ispravno riješiti, au mnogim slučajevima daje još bolje performanse, budući da je potrošnja memorije sužena samo na trenutno računanje - za razliku od čekanja na sljedeći GC ciklus da oslobodi memoriju. Kao rezultat toga, dobili smo vrlo zanimljiv način poboljšanja performansi. I prilično moćan - mislim, radio sam takve stvari prilikom obrade podataka za fintech, i to mi je omogućilo da dobijem ubrzanje od oko pet puta. To je prilično velik poticaj, posebno u svijetu u kojem procesori ne postaju brži i još uvijek čekamo poboljšanja.

Karijera inženjera izvedbe

Andrija: Također bih se želio raspitati o karijeri općenito. Postali ste istaknuti svojim JIT radom u HotSpotu, a zatim ste prešli u Azul, koji je također JVM tvrtka. Ali već smo radili više na hardveru nego na softveru. A onda su se iznenada prebacili na Big Data i Machine Learning, a potom i na otkrivanje prijevara. Kako se to dogodilo? To su vrlo različita područja razvoja.

Litica: Programiram dosta dugo i uspio sam pohađati mnogo različitih tečajeva. I kad ljudi kažu: “oh, ti si taj koji je radio JIT za Javu!”, uvijek je smiješno. Ali prije toga radio sam na klonu PostScripta - jezika koji je Apple nekoć koristio za svoje laserske pisače. A prije toga napravio sam implementaciju Forth jezika. Mislim da mi je zajednička tema razvoj alata. Cijeli život izrađujem alate s kojima drugi ljudi pišu svoje cool programe. Ali također sam bio uključen u razvoj operativnih sustava, drajvera, programa za ispravljanje pogrešaka na razini jezgre, jezika za razvoj OS-a, koji su u početku bili trivijalni, ali su s vremenom postajali sve složeniji. Ali glavna tema je i dalje razvoj alata. Veliki dio mog života prošao je između Azula i Suna, a radilo se o Javi. Ali kad sam počeo s velikim podacima i strojnim učenjem, stavio sam svoj otmjeni šešir na glavu i rekao: "Oh, sada imamo netrivijalan problem, a događa se mnogo zanimljivih stvari i ljudi rade stvari." Ovo je izvrstan razvojni put kojim treba krenuti.

Da, stvarno volim distribuirano računalstvo. Moj prvi posao bio je kao student C, na reklamnom projektu. To je bilo distribuirano računalstvo na Zilog Z80 čipovima koji su prikupljali podatke za analogni OCR, proizvedene pravim analognim analizatorom. Bila je to cool i potpuno luda tema. Ali bilo je problema, neki dio nije bio pravilno prepoznat, pa ste morali izvaditi sliku i pokazati je osobi koja je već znala čitati očima i javiti što piše, pa su postojali poslovi s podacima, a ovi poslovi imali svoj jezik. Postojao je backend koji je sve to obrađivao - Z80 koji je radio paralelno s vt100 terminalima koji su radili - jedan po osobi, a postojao je i model paralelnog programiranja na Z80. Neki zajednički dio memorije koji dijele svi Z80 unutar zvjezdaste konfiguracije; Backplane se također dijelio, a pola RAM-a dijelilo se unutar mreže, a druga polovica je bila privatna ili je išla na nešto drugo. Značajno složen paralelni distribuirani sustav sa dijeljenom... poludijeljenom memorijom. Kad je to bilo... ne mogu se ni sjetiti, negdje sredinom 80-ih. Prilično davno. 
Da, pretpostavimo da je 30 godina dosta davno. Problemi povezani s distribuiranim računalstvom postoje već dosta dugo; ljudi su dugo bili u ratu s Beowulf- grozdovi. Takvi klasteri izgledaju kao... Na primjer: postoji Ethernet i vaš brzi x86 je spojen na ovaj Ethernet, a sada želite dobiti lažnu zajedničku memoriju, jer tada nitko nije mogao raditi distribuirano računalno kodiranje, bilo je preteško i stoga postoji bila je lažna dijeljena memorija sa zaštitnim memorijskim stranicama na x86, a ako ste pisali na ovu stranicu, tada smo rekli drugim procesorima da ako pristupe istoj dijeljenoj memoriji, ona će se morati učitati od vas, a time i nešto poput protokola za podršku pojavila se koherencija predmemorije i softver za to. Zanimljiv koncept. Pravi je problem, naravno, bilo nešto drugo. Sve je ovo funkcioniralo, ali ste brzo dobili probleme s performansama, jer nitko nije razumio modele performansi na dovoljno dobroj razini - koji su obrasci pristupa memoriji bili tamo, kako osigurati da čvorovi ne pingaju jedan drugoga beskrajno i tako dalje.

Ono do čega sam došao u H2O je da su sami programeri odgovorni za određivanje gdje je paralelizam skriven, a gdje nije. Smislio sam model kodiranja koji je pisanje koda visokih performansi učinio lakim i jednostavnim. Ali pisanje sporog koda je teško, izgledat će loše. Morate ozbiljno pokušati napisati spor kod, morat ćete koristiti nestandardne metode. Šifra kočenja vidljiva je na prvi pogled. Kao rezultat toga, obično pišete kod koji se brzo izvodi, ali morate smisliti što učiniti u slučaju zajedničke memorije. Sve je to povezano s velikim nizovima i ponašanje je slično postojanim velikim nizovima u paralelnoj Javi. Mislim, zamislite da dvije niti pišu u paralelni niz, jedna od njih pobjeđuje, a druga prema tome gubi, a vi ne znate koja je koja. Ako nisu promjenjivi, tada redoslijed može biti kakav god želite - i ovo jako dobro funkcionira. Ljudima je stvarno stalo do redoslijeda operacija, oni stavljaju volatile na prava mjesta i očekuju probleme s performansama povezanim s memorijom na pravim mjestima. Inače bi jednostavno napisali kod u obliku petlji od 1 do N, gdje je N nekoliko trilijuna, u nadi da će svi složeni slučajevi automatski postati paralelni - a tu ne radi. Ali u H2O ovo nije ni Java ni Scala; možete to smatrati "Java minus minus" ako želite. Ovo je vrlo jasan stil programiranja i sličan je pisanju jednostavnog C ili Java koda s petljama i nizovima. Ali u isto vrijeme, memorija se može obraditi u terabajtima. I dalje koristim H2O. S vremena na vrijeme koristim ga u različitim projektima - i dalje je najbrža stvar, desetke puta brža od svojih konkurenata. Ako radite s velikim podacima s podacima u stupcima, vrlo je teško nadmašiti H2O.

Tehnički izazovi

Andrija: Što vam je bio najveći izazov u cijeloj karijeri?

Litica: Raspravljamo li o tehničkom ili netehničkom dijelu problema? Rekao bih da najveći izazovi nisu tehnički. 
Što se tiče tehničkih izazova. Jednostavno sam ih porazio. Ne znam ni koji je najveći, ali bilo je dosta zanimljivih za koje je trebalo dosta vremena, psihičke borbe. Kad sam otišao u Sun, bio sam siguran da ću napraviti brzi kompajler, a hrpa starijih je odgovorila da mi to nikad neće uspjeti. Ali slijedio sam ovaj put, napisao kompilator dolje do alokatora registara, i bilo je prilično brzo. Bio je brz kao moderni C1, ali je tada alokator bio puno sporiji, a gledajući unazad, to je bio veliki problem strukture podataka. Trebao mi je da napišem grafički alokator registara i nisam razumio dilemu između izražajnosti koda i brzine, koja je u to doba postojala i bila je vrlo važna. Ispostavilo se da struktura podataka obično premašuje veličinu predmemorije na x86 iz tog vremena, i stoga, ako sam u početku pretpostavio da će alokator registra raditi 5-10 posto ukupnog vremena podrhtavanja, onda se u stvarnosti pokazalo da je 50 posto.

Kako je vrijeme prolazilo, kompajler je postajao čišći i učinkovitiji, prestao je generirati užasan kod u većem broju slučajeva, a performanse su sve više počele nalikovati onima koje proizvodi C prevodilac. Osim ako, naravno, ne napišete neko sranje koje čak ni C ne ubrzava . Ako napišete kod poput C-a, dobit ćete performanse poput C-a u više slučajeva. I što ste išli dalje, to ste češće dobivali kod koji se asimptotski poklapao s razinom C, alokator registara je počeo izgledati kao nešto potpuno... bez obzira radi li vaš kod brzo ili sporo. Nastavio sam raditi na alokatoru kako bih napravio bolje odabire. Postao je sve sporiji i sporiji, ali je davao sve bolje i bolje rezultate u slučajevima u kojima se nitko drugi nije mogao nositi. Mogao bih zaroniti u alokator registara, tamo utrošiti mjesec dana rada, i odjednom bi se cijeli kod počeo izvršavati 5% brže. To se događalo s vremena na vrijeme i razdjelnik je postao svojevrsno umjetničko djelo - svi su ga voljeli ili mrzili, a ljudi s akademije postavljali su pitanja na temu "zašto se sve ovako radi", zašto ne linijski pregled, i koja je razlika. Odgovor je i dalje isti: alokator koji se temelji na bojanju grafikona plus vrlo pažljiv rad s kodom međuspremnika jednako je oružju pobjede, najboljoj kombinaciji koju nitko ne može pobijediti. A ovo je prilično neočita stvar. Sve ostalo što kompilator tamo radi su prilično dobro proučene stvari, iako su i one dovedene do razine umjetnosti. Uvijek sam radio stvari koje su kompilator trebale pretvoriti u umjetničko djelo. Ali ništa od toga nije bilo ništa neobično - osim registratora. Trik je u tome da budete oprezni odsjeći pod opterećenjem i, ako se to dogodi (mogu detaljnije objasniti ako me zanima), to znači da možete agresivnije ući u inline, bez rizika od pada zbog preloma u rasporedu izvedbe. U to je vrijeme postojala hrpa kompajlera punog formata, oblijepljenih ukrasima i zviždaljkama, koji su imali dodjeljivače registara, ali nitko drugi to nije mogao učiniti.

Problem je u tome što ako dodate metode koje su podložne inliningu, povećavajući i povećavajući područje inlininga, skup korištenih vrijednosti trenutno nadmašuje broj registara, pa ih morate rezati. Kritična razina obično dolazi kada alokator odustane, a jedan dobar kandidat za izlijevanje vrijedi drugog, prodat ćete neke općenito divlje stvari. Vrijednost ugradnje ovdje je u tome što gubite dio režijskih troškova, režijskih troškova za pozivanje i spremanje, možete vidjeti vrijednosti unutra i možete ih dodatno optimizirati. Cijena ugradnje je da se formira veliki broj živih vrijednosti, a ako vaš registarski alokator izgori više nego što je potrebno, odmah gubite. Stoga većina alokatora ima problem: kada inlining prijeđe određenu liniju, sve na svijetu počinje se smanjivati ​​i produktivnost se može baciti u zahodsku školjku. Oni koji implementiraju kompilator dodaju neke heuristike: na primjer, da prestanu s ugradnjom, počevši od neke dovoljno velike veličine, jer će dodjele uništiti sve. Ovako nastaje krivuda u grafikonu performansi - inline, inline, izvedba polako raste - i onda bum! – padne kao brzi džak jer si previše podnio. Ovako je sve funkcioniralo prije pojave Jave. Java zahtijeva puno više umetanja, pa sam svoj alokator morao učiniti mnogo agresivnijim kako bi se izravnao umjesto da se ruši, a ako ugradite previše, počinje se razlijevati, ali tada ipak dolazi trenutak "nema više prelijevanja". Ovo je zanimljivo opažanje i došlo mi je niotkuda, nije očito, ali se dobro isplatilo. Prihvatio sam agresivno inlining i to me odvelo na mjesta gdje Java i C performanse rade jedna uz drugu. Stvarno su blizu - mogu napisati Java kod koji je značajno brži od C koda i slične stvari, ali u prosjeku, u velikoj slici stvari, oni su otprilike usporedivi. Mislim da je dio ove zasluge alokator registra, koji mi omogućuje umetanje što je gluplje moguće. Samo ucrtam sve što vidim. Ovdje se postavlja pitanje radi li alokator dobro, je li rezultat inteligentan radni kod. Ovo je bio veliki izazov: razumjeti sve ovo i učiniti da funkcionira.

Malo o dodjeli registara i više jezgri

Vladimir: Problemi poput dodjele registara čine se kao neka vječna, beskrajna tema. Pitam se je li ikada postojala ideja koja se činila obećavajućom, a onda je propala u praksi?

Litica: Sigurno! Dodjela registra je područje u kojem pokušavate pronaći neke heuristike za rješavanje NP-kompletnog problema. I nikada ne možete postići savršeno rješenje, zar ne? Ovo je jednostavno nemoguće. Gle, kompilacija Ahead of Time - također loše radi. Razgovor se ovdje vodi o nekim prosječnim slučajevima. O tipičnoj izvedbi, tako da možete otići i izmjeriti nešto što mislite da je dobra tipična izvedba - na kraju krajeva, radite na tome da je poboljšate! Dodjela registra je tema o izvedbi. Nakon što imate prvi prototip, on radi i slika ono što je potrebno, počinje rad na izvedbi. Trebate naučiti dobro mjeriti. Zašto je to važno? Ako imate jasne podatke, možete pogledati različita područja i vidjeti: da, ovdje je pomoglo, ali tu je sve puklo! Dođu neke dobre ideje, dodate nove heuristike i odjednom sve počne raditi malo bolje u prosjeku. Ili se ne pokreće. Imao sam hrpu slučajeva u kojima smo se borili za pet posto učinka koji je razlikovao naš razvoj od prethodnog alokatora. I svaki put to izgleda ovako: negdje dobiješ, negdje izgubiš. Ako imate dobre alate za analizu učinka, možete pronaći gubitničke ideje i razumjeti zašto ne uspijevaju. Možda je vrijedno ostaviti sve kako jest, ili možda ozbiljnije pristupiti finom podešavanju, ili otići van i popraviti nešto drugo. To je cijela hrpa stvari! Napravio sam ovaj cool hack, ali trebam i ovaj, i ovaj, i ovaj - a njihova ukupna kombinacija daje neka poboljšanja. I usamljenici mogu propasti. Ovo je priroda izvedbenog rada na NP-kompletnim problemima.

Vladimir: Čovjek ima osjećaj da su stvari poput slikanja u alokatorima problem koji je već riješen. Pa tebi je odlučeno, sudeći po ovome što pričaš, pa jel se onda uopće isplati...

Litica: Nije riješeno kao takvo. Vi ste ti koji to morate pretvoriti u "riješeno". Ima teških problema i treba ih rješavati. Nakon što to učinite, vrijeme je za rad na produktivnosti. Ovom poslu morate pristupiti u skladu s tim - napraviti benchmarkove, prikupiti metrike, objasniti situacije kada je, kada ste se vratili na prethodnu verziju, vaš stari hack ponovno počeo raditi (ili obrnuto, prestao). I ne odustaj dok nešto ne postigneš. Kao što sam već rekao, ako postoje cool ideje koje nisu uspjele, ali u području dodjele registara ideja to je otprilike beskonačno. Možete, primjerice, čitati znanstvene publikacije. Iako se sada ovo područje počelo kretati mnogo sporije i postalo je jasnije nego u mladosti. Međutim, postoji bezbroj ljudi koji rade u ovom području i sve su njihove ideje vrijedne isprobavanja, sve čekaju na svoja krila. I ne možete reći koliko su dobri ako ih ne probate. Koliko se dobro integriraju sa svim ostalim u vašem alokatoru, jer alokator radi puno stvari, a neke ideje neće raditi u vašem specifičnom alokatoru, ali u drugom alokatoru hoće lako. Glavni način pobjede za alokatora je izvlačenje sporih stvari izvan glavne staze i prisiljavanje da se razdvoje duž granica sporih staza. Dakle, ako želite pokrenuti GC, ići sporim putem, deoptimizirati, izbaciti iznimku, sve te stvari - znate da su te stvari relativno rijetke. I stvarno su rijetki, provjerio sam. Obavljate dodatni posao i to uklanja mnoga ograničenja na ovim sporim stazama, ali to zapravo nije važno jer su spore i njima se rijetko putuje. Na primjer, nulti pokazivač - to se nikad ne događa, zar ne? Morate imati nekoliko putova za različite stvari, ali oni ne bi trebali smetati glavnom. 

Vladimir: Što mislite o višejezgrenim jezgrama, kada ih ima na tisuće odjednom? Je li ovo korisna stvar?

Litica: Uspjeh GPU-a pokazuje da je vrlo koristan!

Vladimir: Oni su prilično specijalizirani. Što je s procesorima opće namjene?

Litica: Pa, to je bio Azulov poslovni model. Odgovor se vratio u doba kada su ljudi stvarno voljeli predvidljivu izvedbu. Tada je bilo teško pisati paralelni kod. Model kodiranja H2O vrlo je skalabilan, ali nije model opće namjene. Možda malo općenitije nego kada koristite GPU. Govorimo li o složenosti razvoja takve stvari ili složenosti korištenja? Na primjer, Azul me naučio zanimljivu lekciju, prilično neočitu: mali cacheovi su normalni. 

Najveći izazov u životu

Vladimir: Što je s netehničkim izazovima?

Litica: Najveći izazov nije bio biti... dobar i fin prema ljudima. I zbog toga sam se stalno nalazio u krajnje konfliktnim situacijama. One za koje sam znao da stvari idu po zlu, ali nisam znao kako dalje s tim problemima i nisam se mogao nositi s njima. Mnogi dugoročni problemi, koji traju desetljećima, nastali su na taj način. Činjenica da Java ima C1 i C2 prevoditelje izravna je posljedica toga. Izravna posljedica je i činjenica da deset godina zaredom u Javi nije bilo višerazinske kompilacije. Očito je da nam je takav sustav trebao, ali nije jasno zašto ga nije bilo. Imao sam problema s jednim inženjerom... ili grupom inženjera. Jednom davno, kad sam počeo raditi u Sunu, bio sam... Dobro, ne samo tada, ja općenito uvijek imam svoje mišljenje o svemu. I mislio sam da je istina da možeš jednostavno uzeti ovu svoju istinu i reći je u lice. Pogotovo jer sam većinu vremena bio šokantno u pravu. A ako vam se ne sviđa ovakav pristup... pogotovo ako ste očito u krivu i radite gluposti... Općenito, malo ljudi može tolerirati ovakav oblik komunikacije. Iako bi neki mogli, poput mene. Cijeli svoj život izgradio sam na meritokratskim principima. Ako mi nešto krivo pokažeš, odmah ću se okrenuti i reći: rekao si glupost. Ujedno se, naravno, ispričavam i sve to, konstatirati ću zasluge, ako ih bude, te poduzeti druge ispravne radnje. S druge strane, šokantno sam u pravu što se tiče šokantno velikog postotka ukupnog vremena. I ne funkcionira baš najbolje u odnosima s ljudima. Ne pokušavam biti ljubazan, već otvoreno postavljam pitanje. “Ovo nikad neće uspjeti, jer jedan, dva i tri.” A oni su rekli: "Oh!" Bilo je i drugih posljedica koje je vjerojatno bilo bolje ignorirati: na primjer, one koje su dovele do razvoda od moje žene i deset godina depresije nakon toga.

Izazov je borba s ljudima, s njihovom percepcijom što možeš ili ne možeš, što je važno, a što nije. Bilo je mnogo izazova oko stila kodiranja. Još uvijek pišem puno koda, a tih sam dana čak morao usporiti jer sam radio previše paralelnih zadataka i to loše, umjesto da sam se usredotočio na jedan. Gledajući unatrag, napisao sam pola koda za Java JIT naredbu, naredbu C2. Sljedeći najbrži koder je pisao upola sporije, sljedeći upola sporije, i to je bio eksponencijalni pad. Sedma osoba u ovom redu bila je jako, jako spora - to se uvijek događa! Dotaknuo sam se dosta koda. Gledao sam tko je što napisao, bez iznimke, buljio sam u njihov kod, pregledao svakog od njih, i dalje sam nastavio pisati više ja nego bilo tko od njih. Ovaj pristup ne funkcionira dobro s ljudima. Nekima se ovo ne sviđa. A kad se ne snađu, počinju svakakve pritužbe. Na primjer, jednom su mi rekli da prestanem kodirati jer sam pisao previše koda i to je ugrožavalo tim, a sve mi je zvučalo kao šala: stari, ako ostatak tima nestane, a ja nastavim pisati kod, ti Izgubit ću samo pola momčadi. S druge strane, ako nastavim pisati kod, a vi izgubite pola tima, to zvuči kao vrlo loše upravljanje. Nikada nisam stvarno razmišljao o tome, nikad nisam pričao o tome, ali još uvijek je bilo negdje u mojoj glavi. U pozadini mog uma vrtjela se misao: "Šalite li se svi sa mnom?" Dakle, najveći problem sam bio ja i moji odnosi s ljudima. Sada puno bolje razumijem sebe, dugo sam bio timski vođa programera, a sada direktno kažem ljudima: znate, ja sam takav kakav jesam, i vi ćete se morati nositi sa mnom - je li u redu da stojim ovdje? I kad su se počeli time baviti, sve je funkcioniralo. Zapravo, nisam ni loša ni dobra, nemam nikakvih loših namjera ni sebičnih težnji, to je samo moja bit, s kojom treba nekako živjeti.

Andrija: Nedavno su svi počeli govoriti o samosvijesti za introverte i mekim vještinama općenito. Što možete reći o ovome?

Litica: Da, to je bio uvid i lekcija koju sam naučio nakon razvoda od supruge. Ono što sam naučila od razvoda je razumijevanje same sebe. Tako sam počeo razumijevati druge ljude. Shvatite kako ova interakcija funkcionira. To je dovelo do otkrića jedno za drugim. Postojala je svijest tko sam i što predstavljam. Što radim: ili sam zaokupljen zadatkom, ili izbjegavam sukob, ili nešto treće - a ova razina samosvijesti stvarno pomaže da se držim pod kontrolom. Nakon ovoga sve ide puno lakše. Jedna stvar koju sam otkrio ne samo kod sebe, već i kod drugih programera je nemogućnost verbaliziranja misli kada ste u stanju emocionalnog stresa. Na primjer, sjedite tamo i kodirate, u stanju protoka, a onda vam dotrče i počnu histerično vrištati da je nešto pokvareno i da će sada protiv vas biti poduzete ekstremne mjere. I ne možete reći ni riječ jer ste u stanju emocionalnog stresa. Stečeno znanje vam omogućuje da se pripremite za ovaj trenutak, preživite ga i krenete prema planu povlačenja, nakon kojeg možete nešto učiniti. Pa da, kada počnete shvaćati kako sve to funkcionira, to je veliki događaj koji vam mijenja život. 
Ni sam nisam mogao pronaći prave riječi, ali sam zapamtio slijed radnji. Poanta je u tome da je ova reakcija koliko fizička toliko i verbalna, i treba vam prostora. Takav prostor, u zen smislu. Upravo to treba objasniti, a onda se odmah odmaknuti – čisto fizički odmaknuti. Kad šutim verbalno, mogu emocionalno obraditi situaciju. Dok adrenalin dolazi do vašeg mozga, prebacuje vas u način borbe ili bijega, više ne možete ništa reći, ne - sada ste idiot, inženjer bičevanja, nesposoban pristojno odgovoriti ili čak zaustaviti napad, a napadač je slobodan napadati iznova i iznova. Prvo morate ponovno postati ono što jeste, povratiti kontrolu, izaći iz načina "bori se ili bježi".

A za to nam je potreban verbalni prostor. Samo slobodan prostor. Ako uopće išta kažete, onda možete reći upravo to, a onda otići i stvarno pronaći “prostor” za sebe: idite u šetnju parkom, zaključajte se pod tušem - nema veze. Glavno je da se privremeno isključite iz te situacije. Čim se isključite barem na nekoliko sekundi, kontrola se vraća, počinjete trezveno razmišljati. “Dobro, nisam nikakav idiot, ne radim gluposti, ja sam prilično korisna osoba.” Nakon što ste se uspjeli uvjeriti, vrijeme je da prijeđete na sljedeću fazu: razumijevanje onoga što se dogodilo. Bili ste napadnuti, napad je došao odakle ga niste očekivali, bila je to nečasna, podla zasjeda. To je loše. Sljedeći korak je razumjeti zašto je to napadaču trebalo. Stvarno zašto? Možda zato što je i sam bijesan? Zašto je ljut? Na primjer, jer je sam sebe zeznuo i ne može prihvatiti odgovornost? Ovo je način na koji pažljivo rješavate cijelu situaciju. Ali to zahtijeva manevarski prostor, verbalni prostor. Prvi korak je prekid verbalnog kontakta. Izbjegavajte raspravu riječima. Otkažite, otiđite što je brže moguće. Ako je u pitanju telefonski razgovor, samo poklopi - to je vještina koju sam naučio u komunikaciji s bivšom suprugom. Ako razgovor ne ide dobro, samo recite "zbogom" i spustite slušalicu. S druge strane slušalice: "bla bla bla", vi odgovarate: "da, ćao!" i spusti slušalicu. Samo prekini razgovor. Pet minuta kasnije, kad vam se vrati sposobnost razumnog razmišljanja, malo ste se ohladili, postaje moguće razmišljati o svemu, što je bilo i što će biti. I počnite formulirati promišljen odgovor, umjesto da reagirate samo iz emocija. Za mene je proboj u samosvijesti bila upravo činjenica da u slučaju emocionalnog stresa ne mogu govoriti. Izlazak iz ovog stanja, razmišljanje i planiranje kako reagirati i kompenzirati probleme – to su pravi koraci u slučaju kada ne možete govoriti. Najlakši način je pobjeći od situacije u kojoj se emocionalni stres manifestira i jednostavno prestati sudjelovati u tom stresu. Nakon toga postaješ sposoban misliti, kada možeš misliti, postaješ sposoban govoriti, i tako dalje.

Usput, na sudu vam to pokušava učiniti suprotni odvjetnik - sada je jasno zašto. Jer ima sposobnost potisnuti vas do takvog stanja da ne možete ni izgovoriti svoje ime, na primjer. U vrlo stvarnom smislu, nećete moći govoriti. Ako vam se to dogodi i ako znate da ćete se naći na mjestu gdje se vode verbalne bitke, na mjestu poput suda, onda možete doći sa svojim odvjetnikom. Odvjetnik će stati u vašu obranu i zaustaviti verbalni napad, i to na potpuno legalan način, a izgubljeni zen prostor će vam se vratiti. Recimo, nekoliko puta sam morao zvati svoju obitelj, sudac je bio vrlo prijateljski raspoložen oko toga, ali je protivnički odvjetnik vrištao i vikao na mene, nisam mogao doći ni do riječi. U tim slučajevima najbolje mi odgovara korištenje posrednika. Medijator zaustavlja sav taj pritisak koji se na vas slijeva u neprekidnom mlazu, nalazite potreban zen prostor, a s njim se vraća i sposobnost govora. To je cijelo jedno polje znanja u kojem ima puno toga za proučavati, puno toga za otkriti u sebi, a sve se to pretvara u strateške odluke na visokoj razini koje su različite za različite ljude. Neki ljudi nemaju gore opisane probleme; obično ih nemaju ljudi koji su profesionalni prodavači. Svi ti ljudi koji od riječi zarađuju za život - poznati pjevači, pjesnici, vjerski poglavari i političari, uvijek imaju nešto za reći. Oni nemaju takvih problema, ali ja ih imam.

Andrija: Bilo je... neočekivano. Super, već smo dosta pričali i vrijeme je da završimo ovaj intervju. Svakako ćemo se naći na konferenciji i moći ćemo nastaviti taj dijalog. Vidimo se u Hidri!

Razgovor s Cliffom možete nastaviti na Hydra 2019 konferenciji koja će se održati 11. i 12. srpnja 2019. u St. Doći će s izvješćem "Iskustvo transakcijske memorije hardvera Azul". Ulaznice se mogu kupiti na službenoj web stranici.

Izvor: www.habr.com

Dodajte komentar