Skvelý rozhovor s Cliffom Clickom, otcom kompilácie JIT v Jave

Skvelý rozhovor s Cliffom Clickom, otcom kompilácie JIT v JaveCliff Click — CTO Cratus (IoT senzory pre zlepšovanie procesov), zakladateľ a spoluzakladateľ niekoľkých startupov (vrátane Rocket Realtime School, Neurensic a H2O.ai) s niekoľkými úspešnými exitmi. Cliff napísal svoj prvý kompilátor vo veku 15 rokov (Pascal pre TRS Z-80)! Je známy svojou prácou na C2 v Jave (The Sea of ​​​​Nodes IR). Tento kompilátor ukázal svetu, že JIT dokáže produkovať kvalitný kód, čo bol jeden z faktorov vzniku Javy ako jednej z hlavných moderných softvérových platforiem. Potom Cliff pomohol Azul Systems vybudovať 864-jadrový mainframe s čistým Java softvérom, ktorý podporoval GC pauzy na 500-gigabajtovej halde do 10 milisekúnd. Vo všeobecnosti sa Cliffovi podarilo pracovať na všetkých aspektoch JVM.

 
Tento habrapost je skvelý rozhovor s Cliffom. Budeme hovoriť o nasledujúcich témach:

  • Prechod na nízkoúrovňové optimalizácie
  • Ako urobiť veľký refaktoring
  • Nákladový model
  • Nízkoúrovňové optimalizačné školenie
  • Praktické príklady zlepšenia výkonu
  • Prečo si vytvoriť vlastný programovací jazyk
  • Kariéra výkonového inžiniera
  • Technické výzvy
  • Trochu o prideľovaní registrov a viacjadrách
  • Najväčšia výzva v živote

Rozhovory vedú:

  • Andrej Satarin od Amazon Web Services. Vo svojej kariére sa mu podarilo pracovať v úplne iných projektoch: testoval distribuovanú databázu NewSQL v Yandex, cloudový detekčný systém v Kaspersky Lab, hru pre viacerých hráčov v Mail.ru a službu na výpočet devízových cien v Deutsche Bank. Záujem o testovanie rozsiahlych backendových a distribuovaných systémov.
  • Vladimír Sitnikov od spoločnosti Netcracker. Desať rokov práce na výkone a škálovateľnosti operačného systému NetCracker, softvéru používaného telekomunikačnými operátormi na automatizáciu procesov správy sietí a sieťových zariadení. Zaujímate sa o problémy s výkonom Java a Oracle Database. Autor viac ako tuctu vylepšení výkonu v oficiálnom ovládači PostgreSQL JDBC.

Prechod na nízkoúrovňové optimalizácie

Andrew: Si veľké meno vo svete kompilácie JIT, Javy a práce s výkonom všeobecne, však? 

Cliff: Je to tak!

Andrew: Začnime niekoľkými všeobecnými otázkami o výkone práce. Čo si myslíte o výbere medzi optimalizáciou na vysokej a nízkej úrovni, ako je napríklad práca na úrovni CPU?

Cliff: Áno, všetko je tu jednoduché. Najrýchlejší kód je ten, ktorý sa nikdy nespustí. Preto vždy musíte začať od vysokej úrovne, pracovať na algoritmoch. Lepší zápis O porazí horší zápis O, pokiaľ nezasiahnu nejaké dostatočne veľké konštanty. Veci nízkej úrovne idú ako posledné. Zvyčajne, ak ste dostatočne dobre zoptimalizovali zvyšok svojho zásobníka a stále vám ostali nejaké zaujímavé veci, je to nízka úroveň. Ako však začať od vysokej úrovne? Ako viete, že sa vykonalo dosť práce na vysokej úrovni? No... v žiadnom prípade. Neexistujú žiadne hotové recepty. Musíte pochopiť problém, rozhodnúť sa, čo budete robiť (aby ste v budúcnosti nerobili zbytočné kroky) a potom môžete odhaliť profiler, ktorý môže povedať niečo užitočné. V určitom okamihu si uvedomíte, že ste sa zbavili nepotrebných vecí a je čas urobiť nejaké jemné doladenie na nízkej úrovni. Toto je určite zvláštny druh umenia. Veľa ľudí robí nepotrebné veci, no pohybujú sa tak rýchlo, že nemajú čas starať sa o produktivitu. Ale to je dovtedy, kým otázka nevyvstane priamočiaro. Zvyčajne 99% času nikoho nezaujíma, čo robím, až do momentu, keď na kritickej ceste príde dôležitá vec, ktorá nikoho nezaujíma. A tu vám každý začne nadávať na to, „prečo to od samého začiatku nefungovalo dokonale“. Vo všeobecnosti je vo výkone vždy čo zlepšovať. Ale v 99% prípadov nemáte žiadne potenciálne kontakty! Len sa snažíte, aby niečo fungovalo a v tomto procese prídete na to, čo je dôležité. Nikdy nemôžete dopredu vedieť, že tento kúsok musí byť dokonalý, takže vlastne musíte byť dokonalí vo všetkom. Ale to je nemožné a vy to neurobíte. Vždy je potrebné opraviť veľa vecí – a to je úplne normálne.

Ako urobiť veľký refaktoring

Andrew: Ako pracujete na predstavení? Ide o prierezový problém. Museli ste napríklad niekedy pracovať na problémoch, ktoré vznikajú priesečníkom mnohých existujúcich funkcií?

Cliff: Snažím sa tomu vyhýbať. Ak viem, že výkon bude problémom, premýšľam o tom skôr, ako začnem kódovať, najmä s dátovými štruktúrami. Toto všetko však často zistíte až neskôr. A potom musíte ísť do extrémnych opatrení a urobiť to, čo nazývam „prepísať a dobyť“: musíte chytiť dostatočne veľký kus. Časť kódu bude musieť byť stále prepísaná kvôli problémom s výkonom alebo niečomu inému. Bez ohľadu na dôvod prepisovania kódu je takmer vždy lepšie prepísať väčší kus ako menší kus. V tomto momente sa všetci začnú triasť strachom: "Ó môj bože, nemôžete sa dotknúť toľkého kódu!" Ale v skutočnosti tento prístup takmer vždy funguje oveľa lepšie. Musíte okamžite prijať veľký problém, nakresliť okolo neho veľký kruh a povedať: Prepíšem všetko vnútri kruhu. Okraj je oveľa menší ako obsah v ňom, ktorý je potrebné nahradiť. A ak vám takéto vytýčenie hraníc umožní robiť prácu vo vnútri dokonale, ruky máte voľné, robte si, čo chcete. Keď pochopíte problém, proces prepisovania je oveľa jednoduchší, takže si poriadne zahryznite!
Zároveň, keď urobíte veľké prepísanie a uvedomíte si, že výkon bude problémom, môžete sa o to okamžite začať obávať. Zvyčajne sa to zmení na jednoduché veci, ako napríklad „nekopírujte údaje, spravujte údaje čo najjednoduchšie, zmenšite ich“. Pri veľkých prepisoch existujú štandardné spôsoby na zlepšenie výkonu. A takmer vždy sa točia okolo dát.

Nákladový model

Andrew: V jednom z podcastov ste hovorili o nákladových modeloch v kontexte produktivity. Môžeš vysvetliť, čo si tým chcel povedať?

Cliff: Určite. Narodil som sa v dobe, keď bol výkon procesora mimoriadne dôležitý. A táto éra sa opäť vracia - osud nie je bez irónie. Začal som žiť v časoch osembitových strojov, môj prvý počítač pracoval s 256 bajtmi. Presne bajtov. Všetko bolo veľmi malé. Inštrukcie sa museli počítať, a keď sme sa začali posúvať v zásobníku programovacích jazykov, jazyky naberali stále viac a viac. Bol tam Assembler, potom Basic, potom C a C sa postaralo o veľa detailov, ako je pridelenie registra a výber inštrukcií. Ale tam bolo všetko celkom jasné a ak by som urobil ukazovateľ na inštanciu premennej, potom by som dostal zaťaženie a cena tejto inštrukcie je známa. Hardvér produkuje určitý počet strojových cyklov, takže rýchlosť vykonávania rôznych vecí sa dá vypočítať jednoducho sčítaním všetkých inštrukcií, ktoré sa chystáte spustiť. Každé porovnanie/test/pobočka/hovor/načítanie/obchod sa dá sčítať a povedať: to je čas vykonania pre vás. Pri práci na zlepšení výkonu si určite dáte pozor na to, aké čísla zodpovedajú malým horúcim cyklom. 
Ale akonáhle prejdete na Javu, Python a podobné veci, veľmi rýchlo sa vzdialite od hardvéru nízkej úrovne. Aké sú náklady na volanie getter v jazyku Java? Ak je JIT v HotSpot správny vložené, načíta sa, ale ak to neurobí, bude to volanie funkcie. Keďže hovor prebieha v horúcej slučke, prepíše všetky ostatné optimalizácie v tejto slučke. Preto budú skutočné náklady oveľa vyššie. A okamžite stratíte možnosť pozrieť sa na kúsok kódu a pochopiť, že by sme ho mali vykonať z hľadiska rýchlosti procesora, pamäte a použitej vyrovnávacej pamäte. To všetko sa stáva zaujímavým, len ak sa do predstavenia naozaj dostanete.
Teraz sme sa ocitli v situácii, keď sa rýchlosť procesorov za desaťročie takmer nezvýšila. Staré časy sú späť! Už nemôžete počítať s dobrým jednovláknovým výkonom. Ale ak sa zrazu dostanete do paralelných počítačov, je to neuveriteľne ťažké, každý sa na vás pozerá ako na Jamesa Bonda. Desaťnásobné zrýchlenie tu väčšinou nastáva na miestach, kde niekto niečo pokazil. Súbeh si vyžaduje veľa práce. Ak chcete dosiahnuť XNUMX-násobné zrýchlenie, musíte pochopiť nákladový model. Čo a koľko to stojí? A aby ste to dosiahli, musíte pochopiť, ako jazyk sedí na základnom hardvéri.
Martin Thompson zvolil pre svoj blog skvelé slovo Mechanická sympatia! Musíte pochopiť, čo bude hardvér robiť, ako presne to bude robiť a prečo to robí. Pomocou tohto je pomerne jednoduché začať počítať pokyny a zistiť, kam ide čas vykonania. Ak nemáte príslušný výcvik, hľadáte len čiernu mačku v tmavej miestnosti. Vidím ľudí, ktorí neustále optimalizujú výkon, ktorí nemajú ani poňatia, čo do pekla robia. Veľmi trpia a nerobia veľké pokroky. A keď vezmem ten istý kúsok kódu, vložím pár malých hackov a získam päť- alebo desaťnásobné zrýchlenie, povedia si: no, to nie je fér, už sme vedeli, že ste lepší. Úžasný. O čom to hovorím... nákladový model je o tom, aký kód napíšete a ako rýchlo v priemere beží vo veľkom.

Andrew: A ako si udržíš taký objem v hlave? Dá sa to dosiahnuť väčšími skúsenosťami, alebo? Odkiaľ pochádza takáto skúsenosť?

Cliff: No, nezískal som svoje skúsenosti najjednoduchším spôsobom. Programoval som v Assembly ešte v časoch, keď ste rozumeli každej jednej inštrukcii. Znie to hlúpo, ale odvtedy mi inštrukčná sada Z80 zostala vždy v hlave, v pamäti. Nepamätám si mená ľudí do minúty hovoru, ale pamätám si kód napísaný pred 40 rokmi. Je to smiešne, vyzerá to ako syndróm"idiotský vedec".

Nízkoúrovňové optimalizačné školenie

Andrew: Existuje jednoduchší spôsob, ako sa dostať dovnútra?

Cliff: Áno a nie. Hardvér, ktorý všetci používame, sa časom až tak veľmi nezmenil. Každý používa x86, s výnimkou smartfónov Arm. Ak nerobíte nejaký druh hardcore vkladania, robíte to isté. Dobre, ďalej. Pokyny sa tiež po stáročia nezmenili. Musíte ísť a niečo napísať do zhromaždenia. Nie veľa, ale dosť na to, aby som tomu začal rozumieť. Usmievate sa, ale ja hovorím úplne vážne. Musíte pochopiť súlad medzi jazykom a hardvérom. Potom musíte ísť a trochu písať a vytvoriť malý kompilátor hračiek pre jazyk malých hračiek. Toy-like znamená, že to musí byť vyrobené v primeranom čase. Môže to byť super jednoduché, ale musí to generovať pokyny. Akt generovania inštrukcie vám pomôže pochopiť nákladový model pre most medzi vysokoúrovňovým kódom, ktorý každý píše, a strojovým kódom, ktorý beží na hardvéri. Táto korešpondencia bude vpálená do mozgu v čase, keď je kompilátor napísaný. Dokonca aj ten najjednoduchší kompilátor. Potom sa môžete začať pozerať na Javu a na skutočnosť, že jej sémantická priepasť je oveľa hlbšia a je oveľa ťažšie nad ňou stavať mosty. Na Jáve je oveľa ťažšie pochopiť, či náš most dopadol dobre alebo zle, čo spôsobí jeho rozpad a čo nie. Potrebujete však nejaký počiatočný bod, kde sa pozriete na kód a pochopíte: „Áno, tento getter by mal byť vždy vložený.“ A potom sa ukáže, že sa to niekedy stane, okrem situácie, keď sa metóda stane príliš veľkou a JIT začne všetko vkladať. Výkonnosť takýchto miest sa dá predvídať okamžite. Getre zvyčajne fungujú dobre, ale potom sa pozriete na veľké horúce slučky a uvedomíte si, že sa tam vznášajú nejaké volania funkcií, ktoré nevedia, čo robia. Toto je problém rozšíreného používania getrov, dôvod, prečo nie sú inline, je ten, že nie je jasné, či ide o getre. Ak máte super malú základňu kódu, môžete si ju jednoducho zapamätať a potom povedať: toto je getter a toto je nastavovač. Vo veľkej kódovej základni každá funkcia žije svojou vlastnou históriou, ktorá vo všeobecnosti nie je nikomu známa. Profiler hovorí, že sme stratili 24% času na nejakej slučke a aby sme pochopili, čo táto slučka robí, musíme sa pozrieť na každú funkciu vo vnútri. Nie je možné to pochopiť bez preštudovania funkcie, čo vážne spomaľuje proces porozumenia. Preto nepoužívam getre a setre, dosiahol som nový level!
Kde získať nákladový model? No, dá sa niečo prečítať, samozrejme... Ale myslím si, že najlepší spôsob je konať. Vytvorenie malého kompilátora bude najlepší spôsob, ako pochopiť nákladový model a napasovať ho do vlastnej hlavy. Malý kompilátor, ktorý by sa hodil na programovanie mikrovlnky, je úloha pre začiatočníka. No, myslím, že ak už máte programátorské schopnosti, tak by to malo stačiť. Všetky tieto veci, ako je analýza reťazca, ktorý máte ako nejaký algebraický výraz, extrahovanie pokynov pre matematické operácie odtiaľ v správnom poradí, prevzatie správnych hodnôt z registrov - to všetko sa robí naraz. A kým to urobíte, zapíše sa to do vášho mozgu. Myslím, že každý vie, čo robí kompilátor. A to umožní pochopiť nákladový model.

Praktické príklady zlepšenia výkonu

Andrew: Na čo si ešte dať pozor pri práci na produktivite?

Cliff: Dátové štruktúry. Mimochodom, áno, tieto hodiny som už dlho neučil... Raketová škola. Bola to zábava, ale vyžadovalo si to veľa úsilia a ja mám tiež život! OK. Takže v jednej z veľkých a zaujímavých tried „Kam ide váš výkon“ som dal študentom príklad: dva a pol gigabajtu fintech dát bolo načítaných zo súboru CSV a potom museli vypočítať počet predaných produktov. . Pravidelné trhové údaje. UDP pakety konvertované do textového formátu od 70. rokov. Chicago Mercantile Exchange – všelijaké veci ako maslo, kukurica, sójové bôby a podobne. Bolo potrebné spočítať tieto produkty, počet transakcií, priemerný objem pohybu finančných prostriedkov a tovaru atď. Je to celkom jednoduchá obchodná matematika: nájdite kód produktu (to je 1-2 znaky v tabuľke hash), získajte sumu, pridajte ju do jednej z obchodných sád, pridajte objem, pridajte hodnotu a niekoľko ďalších vecí. Veľmi jednoduchá matematika. Implementácia hračky bola veľmi priamočiara: všetko je v súbore, súbor čítam a pohybujem sa v ňom, pričom jednotlivé záznamy rozdeľujem do Java reťazcov, hľadám v nich potrebné veci a sčítavam ich podľa vyššie popísanej matematiky. A funguje to pri nízkej rýchlosti.

S týmto prístupom je zrejmé, čo sa deje, a paralelné výpočty nepomôžu, však? Ukazuje sa, že päťnásobný nárast výkonu je možné dosiahnuť jednoduchým výberom správnych dátových štruktúr. A to prekvapuje aj skúsených programátorov! V mojom konkrétnom prípade bol trik taký, že by ste nemali prideľovať pamäť v horúcej slučke. Nie je to celá pravda, ale vo všeobecnosti by ste nemali zvýrazňovať „raz za X“, keď je X dostatočne veľké. Keď má X dva a pol gigabajtu, nemali by ste nič prideľovať „raz na písmeno“ alebo „raz na riadok“ alebo „raz na pole“, nič podobné. Tu sa trávi čas. Ako to vôbec funguje? Predstavte si, že volám String.split() alebo BufferedReader.readLine(). Readline vytvorí reťazec zo sady bajtov, ktoré prišli cez sieť, raz pre každý riadok, pre každý zo stoviek miliónov riadkov. Vezmem tento riadok, rozoberiem a vyhodím. Prečo to vyhadzujem - dobre, už som to spracoval, to je všetko. Takže za každý prečítaný bajt z týchto 2.7G sa do riadku zapíšu dva znaky, teda už 5.4G, a už ich nepotrebujem na nič, takže sú vyhodené. Ak sa pozriete na šírku pásma pamäte, načítame 2.7G, ktoré ide cez pamäť a pamäťovú zbernicu v procesore a potom sa dvakrát toľko posiela na linku ležiacu v pamäti a to všetko sa rozstrapká pri vytvorení každého nového riadku. Ale potrebujem si to prečítať, hardvér to číta, aj keď je neskôr všetko ošúchané. A musím si to zapísať, pretože som vytvoril riadok a kešky sú plné - vyrovnávacia pamäť nepojme 2.7G. Takže na každý prečítaný bajt prečítam ďalšie dva bajty a zapíšem ďalšie dva bajty a nakoniec majú pomer 4: 1 - v tomto pomere plytváme šírkou pásma pamäte. A potom sa ukáže, že ak áno String.split() – toto nie je poslednýkrát, vo vnútri môže byť ďalších 6-7 políčok. Takže klasický kód čítania CSV a následnej analýzy reťazcov má za následok stratu šírky pásma pamäte približne 14:1 v porovnaní s tým, čo by ste v skutočnosti chceli mať. Ak tieto výbery vyhodíte, môžete dosiahnuť päťnásobné zrýchlenie.

A nie je to také ťažké. Ak sa pozriete na kód zo správneho uhla, všetko sa stane celkom jednoduchým, keď si uvedomíte problém. Nemali by ste úplne prestať prideľovať pamäť: jediný problém je v tom, že niečo pridelíte a ono to okamžite zahynie a popri tom spáli dôležitý zdroj, ktorým je v tomto prípade šírka pásma pamäte. A to všetko má za následok pokles produktivity. Na x86 zvyčajne potrebujete aktívne napaľovať cykly procesora, ale tu ste spálili celú pamäť oveľa skôr. Riešením je zníženie množstva výboja. 
Ďalšou časťou problému je, že ak spustíte profilovač, keď sa minie pamäťový pás, práve vtedy, keď sa to stane, zvyčajne čakáte, kým sa vyrovnávacia pamäť vráti, pretože je plná odpadu, ktorý ste práve vyprodukovali, všetkých tých riadkov. Preto sa každé načítanie alebo ukladanie spomalí, pretože vedie k vynechaniu vyrovnávacej pamäte – celá vyrovnávacia pamäť sa spomalila a čaká, kým z nej odpadky opustia. Preto profiler zobrazí iba teplý náhodný šum rozmazaný v celej slučke - v kóde nebude žiadna samostatná horúca inštrukcia ani miesto. Iba hluk. A ak sa pozriete na cykly GC, všetky sú mladej generácie a sú super rýchle – maximálne mikrosekundy alebo milisekúndy. Koniec koncov, všetka táto spomienka okamžite zomrie. Vy pridelíte miliardy gigabajtov a on ich odreže, odreže a znova odreže. To všetko sa deje veľmi rýchlo. Ukazuje sa, že existujú lacné cykly GC, teplý hluk počas celého cyklu, ale chceme dosiahnuť 5-násobné zrýchlenie. V tejto chvíli by sa malo niečo uzavrieť vo vašej hlave a znieť: "prečo to?" Pretečenie pamäťového pásu sa v klasickom ladiacom nástroji nezobrazuje, musíte spustiť ladiaci nástroj počítadla výkonu hardvéru a vidieť to sami a priamo. To však nemožno priamo podozrievať z týchto troch príznakov. Tretím príznakom je, keď sa pozriete na to, čo zvýrazníte, opýtate sa profilátora a on odpovie: „Urobili ste miliardu riadkov, ale GC fungovalo zadarmo.“ Akonáhle sa to stane, uvedomíte si, že ste vytvorili príliš veľa objektov a spálili celú pamäťovú dráhu. Existuje spôsob, ako to zistiť, ale nie je to zrejmé. 

Problém je v dátovej štruktúre: holá štruktúra, ktorá je základom všetkého, čo sa deje, je príliš veľká, má 2.7G na disku, takže vytváranie kópie tejto veci je veľmi nežiaduce - chcete ju okamžite načítať zo sieťovej bajtovej vyrovnávacej pamäte do registrov, aby sa päťkrát nečítalo a zapisovalo do riadku tam a späť. Bohužiaľ, Java vám štandardne neposkytuje takúto knižnicu ako súčasť JDK. Ale to je triviálne, však? V podstate ide o 5-10 riadkov kódu, ktoré sa použijú na implementáciu vášho vlastného načítača reťazcov s vyrovnávacou pamäťou, ktorý opakuje správanie triedy reťazcov, pričom je obalom okolo základnej vyrovnávacej pamäte bajtov. V dôsledku toho sa ukáže, že pracujete takmer ako s reťazcami, ale v skutočnosti sa tam presúvajú ukazovatele na vyrovnávaciu pamäť a nespracované bajty sa nikam neskopírujú, a teda sa znova a znova používajú rovnaké vyrovnávacie pamäte a operačný systém si rád vezme na seba veci, na ktoré je určený, ako je skryté dvojité ukladanie týchto bajtových vyrovnávacích pamätí a vy sa už nebudete predierať nekonečným prúdom nepotrebných dát. Mimochodom, chápete, že pri práci s GC je zaručené, že každá alokácia pamäte nebude pre procesor po poslednom cykle GC viditeľná? Preto toto všetko nemôže byť v cache a potom dôjde k 100% zaručenému miss. Pri práci s ukazovateľom na x86 trvá odčítanie registra z pamäte 1-2 hodinové cykly a hneď ako sa to stane, platíte, platíte, platíte, pretože pamäť je celá zapnutá DEVIŤ skrýš – a to sú náklady na pridelenie pamäte. Skutočná hodnota.

Inými slovami, dátové štruktúry je najťažšie zmeniť. A keď si uvedomíte, že ste si vybrali nesprávnu dátovú štruktúru, ktorá neskôr zabije výkon, zvyčajne vás čaká veľa práce, no ak to neurobíte, všetko sa zhorší. V prvom rade sa musíte zamyslieť nad dátovými štruktúrami, to je dôležité. Hlavná cena tu pripadá na tukové dátové štruktúry, ktoré sa začínajú používať v štýle „Dátovú štruktúru X som skopíroval do dátovej štruktúry Y, pretože sa mi viac páči tvar Y“. Ale operácia kopírovania (ktorá sa zdá byť lacná) v skutočnosti plytvá šírkou pásma pamäte a to je miesto, kde je pochovaný všetok premárnený čas vykonávania. Ak mám obrovský reťazec JSON a chcem ho premeniť na štruktúrovaný strom DOM s POJO alebo tak niečo, operácia analýzy tohto reťazca a zostavenie POJO a následného opätovného prístupu k POJO bude mať za následok zbytočné náklady – je to nie lacné. Ibaže ak beháte okolo POJO oveľa častejšie ako okolo šnúrky. Namiesto toho sa môžete namiesto toho pokúsiť dešifrovať reťazec a extrahovať odtiaľ iba to, čo potrebujete, bez toho, aby ste to zmenili na POJO. Ak sa toto všetko deje na ceste, od ktorej sa vyžaduje maximálny výkon, žiadne POJO pre vás, treba sa nejako priamo prekopať do linky.

Prečo si vytvoriť vlastný programovací jazyk

Andrew: Povedali ste, že ak chcete pochopiť nákladový model, musíte si napísať svoj vlastný malý jazyk...

Cliff: Nie jazyk, ale kompilátor. Jazyk a kompilátor sú dve rôzne veci. Najdôležitejší rozdiel je vo vašej hlave. 

Andrew: Mimochodom, pokiaľ viem, experimentujete s vytváraním vlastných jazykov. Prečo?

Cliff: Pretože ja môžem! Som polovičný dôchodca, takže toto je môj koníček. Celý život implementujem jazyky iných ľudí. Tiež som veľa pracoval na svojom štýle kódovania. A tiež preto, že problémy vidím v iných jazykoch. Vidím, že existujú lepšie spôsoby, ako robiť známe veci. A využil by som ich. Už ma nebaví vidieť problémy v sebe, v Jave, v Pythone, v akomkoľvek inom jazyku. React Native, JavaScript a Elm teraz píšem ako hobby, ktoré nie je o dôchodku, ale o aktívnej práci. Píšem aj v Pythone a s najväčšou pravdepodobnosťou budem pokračovať v práci na strojovom učení pre Java backendy. Existuje veľa populárnych jazykov a všetky majú zaujímavé funkcie. Každý je dobrý svojím vlastným spôsobom a môžete sa pokúsiť spojiť všetky tieto funkcie. Takže študujem veci, ktoré ma zaujímajú, správanie jazyka, snažím sa prísť na rozumnú sémantiku. A zatiaľ sa mi to darí! Momentálne bojujem so sémantikou pamäte, pretože ju chcem mať ako v C a Jave a získať silný pamäťový model a sémantiku pamäte pre záťaže a sklady. Zároveň majte automatické odvodzovanie typu ako v Haskell. Tu sa snažím zmiešať odvodenie typu Haskell s prácou s pamäťou v C aj Jave. To je to, čo robím napríklad posledné 2-3 mesiace.

Andrew: Ak vytvoríte jazyk, ktorý preberá lepšie aspekty z iných jazykov, myslíte si, že niekto urobí opak: vezme vaše nápady a použije ich?

Cliff: Presne takto sa objavujú nové jazyky! Prečo je Java podobná C? Pretože C malo dobrú syntax, ktorej každý rozumel a Java sa inšpirovala touto syntaxou, pridala bezpečnosť typov, kontrolu hraníc poľa, GC a tiež zlepšili niektoré veci z C. Pridali svoje vlastné. Ale inšpirovali sa dosť veľa, však? Všetci stoja na pleciach obrov, ktorí prišli pred vami – tak sa robí pokrok.

Andrew: Ako tomu rozumiem, váš jazyk bude v bezpečí pamäte. Rozmýšľali ste nad implementáciou niečoho ako pôžičkový checker od Rustu? Pozreli ste sa naňho, čo si o ňom myslíte?

Cliff: No, písal som C už celé veky, so všetkým tým malloc a zadarmo a manuálne som spravoval životnosť. Viete, 90-95% ručne ovládanej životnosti má rovnakú štruktúru. A robiť to ručne je veľmi, veľmi bolestivé. Bol by som rád, keby vám kompilátor jednoducho povedal, čo sa tam deje a čo ste svojimi činmi dosiahli. Pri niektorých veciach to robí nástroj na kontrolu požičania hneď po vybalení. A mala by automaticky zobrazovať informácie, všetkému rozumieť a ani ma nezaťažovať prezentovaním tohto pochopenia. Musí vykonať aspoň lokálnu únikovú analýzu a iba ak zlyhá, potom musí pridať typové anotácie, ktoré budú popisovať životnosť – a takáto schéma je oveľa zložitejšia ako kontrola výpožičiek alebo vlastne akýkoľvek existujúci kontrolór pamäte. Voľba medzi „všetko je v poriadku“ a „ničomu nerozumiem“ - nie, musí existovať niečo lepšie. 
Takže ako niekto, kto napísal veľa kódu v C, si myslím, že podpora automatického riadenia životnosti je najdôležitejšia vec. Mám tiež dosť toho, koľko Java používa pamäť a hlavnou sťažnosťou je GC. Keď pridelíte pamäť v jazyku Java, nezískate späť pamäť, ktorá bola lokálna pri poslednom cykle GC. V jazykoch s presnejšou správou pamäte to tak nie je. Ak zavoláte malloc, okamžite získate pamäť, ktorá bola zvyčajne práve používaná. Zvyčajne robíte nejaké dočasné veci s pamäťou a okamžite ju vrátite späť. A okamžite sa vráti do bazéna malloc a ďalší cyklus malloc ho znova vytiahne. Preto je skutočné využitie pamäte znížené na množinu živých objektov v danom čase, plus úniky. A ak všetko neunikne úplne neslušným spôsobom, väčšina pamäte skončí vo vyrovnávacej pamäti a procesore a funguje rýchlo. Vyžaduje si to však veľa manuálnej správy pamäte pomocou malloc a bezplatných volaní v správnom poradí na správnom mieste. Hrdza si s tým dokáže sama správne poradiť a v mnohých prípadoch podá ešte lepší výkon, keďže spotreba pamäte je zúžená len na aktuálny výpočet – na rozdiel od čakania na ďalší cyklus GC, aby sa pamäť uvoľnila. Výsledkom je veľmi zaujímavý spôsob, ako zlepšiť výkon. A dosť výkonný - myslím, že som robil takéto veci pri spracovaní údajov pre fintech, a to mi umožnilo dosiahnuť asi päťnásobné zrýchlenie. To je dosť veľká podpora, najmä vo svete, kde procesory nie sú rýchlejšie a stále čakáme na vylepšenia.

Kariéra výkonového inžiniera

Andrew: Tiež by som sa rád spýtal na kariéru všeobecne. Do popredia ste sa dostali vďaka práci JIT v HotSpot a potom ste sa presťahovali do Azul, čo je tiež spoločnosť JVM. Ale už sme pracovali viac na hardvéri ako na softvéri. A potom zrazu prešli na Big Data a Machine Learning a potom na detekciu podvodov. Ako sa to stalo? Ide o veľmi odlišné oblasti vývoja.

Cliff: Programovaniu sa venujem pomerne dlho a podarilo sa mi absolvovať množstvo rôznych kurzov. A keď ľudia hovoria: „Ach, ty si ten, kto robil JIT pre Javu!“, je to vždy zábavné. Predtým som však pracoval na klone PostScriptu – jazyka, ktorý Apple kedysi používal pre svoje laserové tlačiarne. A predtým som vykonal implementáciu jazyka Forth. Myslím, že spoločnou témou je pre mňa vývoj nástrojov. Celý život som vyrábal nástroje, pomocou ktorých iní ľudia píšu svoje skvelé programy. Zaoberal som sa však aj vývojom operačných systémov, ovládačov, debuggerov na úrovni jadra, jazykov pre vývoj OS, čo začalo byť triviálne, no postupom času bolo čoraz zložitejšie. No hlavnou témou je stále vývoj nástrojov. Veľká časť môjho života prešla medzi Azulom a Sunom a bola o Jave. Ale keď som sa dostal do Big Data a Machine Learning, nasadil som si svoj luxusný klobúk a povedal: „Ach, teraz máme netriviálny problém a deje sa veľa zaujímavých vecí a ľudia robia veci.“ Toto je skvelá cesta rozvoja.

Áno, naozaj milujem distribuované počítače. Moja prvá práca bola ako študentka v C na reklamnom projekte. Išlo o distribuované výpočty na čipoch Zilog Z80, ktoré zbierali údaje pre analógové OCR, vyrobené skutočným analógovým analyzátorom. Bola to skvelá a úplne šialená téma. Vyskytli sa však problémy, niektorá časť nebola správne rozpoznaná, takže ste museli vytiahnuť obrázok a ukázať ho osobe, ktorá už vedela čítať očami a hlásiť, čo sa tam píše, a preto boli úlohy s údajmi a tieto úlohy mali svoj vlastný jazyk. Existoval backend, ktorý toto všetko spracovával – Z80 bežiace paralelne s bežiacimi terminálmi vt100 – jeden na osobu, a na Z80 bol paralelný programovací model. Nejaký spoločný kus pamäte zdieľaný všetkými Z80 v rámci hviezdnej konfigurácie; Backplane bola tiež zdieľaná a polovica RAM bola zdieľaná v rámci siete a ďalšia polovica bola súkromná alebo išla do niečoho iného. Zmysluplne komplexný paralelný distribuovaný systém so zdieľanou... polozdieľanou pamäťou. Kedy to bolo... už si ani nepamätám, niekde v polovici 80. rokov. Veľmi dávno. 
Áno, predpokladajme, že 30 rokov je dosť dávno. Problémy súvisiace s distribuovanými počítačmi existujú už dosť dlho, ľudia sú už dlho vo vojne Beowulf- zhluky. Takéto klastre vyzerajú ako... Napríklad: existuje Ethernet a váš rýchly x86 je pripojený k tomuto Ethernetu a teraz chcete získať falošnú zdieľanú pamäť, pretože vtedy nikto nevedel robiť distribuované výpočtové kódovanie, bolo to príliš ťažké a preto tam bola falošná zdieľaná pamäť s ochrannými pamäťovými stránkami na x86 a ak ste napísali na túto stránku, povedali sme ostatným procesorom, že ak pristupujú k rovnakej zdieľanej pamäti, bude potrebné ju načítať od vás, a teda niečo ako protokol na podporu objavila sa koherencia vyrovnávacej pamäte a softvér na to. Zaujímavý koncept. Skutočný problém bol, samozrejme, niečo iné. Toto všetko fungovalo, ale rýchlo ste mali problémy s výkonom, pretože nikto nerozumel výkonnostným modelom na dostatočne dobrej úrovni – aké vzory prístupu do pamäte tam boli, ako zabezpečiť, aby sa uzly navzájom donekonečna nepingovali atď.

V H2O som prišiel na to, že sú to samotní vývojári, ktorí sú zodpovední za určenie, kde je paralelizmus skrytý a kde nie. Prišiel som s modelom kódovania, vďaka ktorému bolo písanie vysokovýkonného kódu jednoduché a jednoduché. Ale písať pomaly bežiaci kód je ťažké, bude to vyzerať zle. Musíte sa vážne pokúsiť napísať pomalý kód, budete musieť použiť neštandardné metódy. Brzdový kód je viditeľný na prvý pohľad. Výsledkom je, že zvyčajne píšete kód, ktorý beží rýchlo, no musíte prísť na to, čo robiť v prípade zdieľanej pamäte. Toto všetko je viazané na veľké polia a správanie sa tam podobá na nevolatilné veľké polia v paralelnej Jave. Predstavte si, že dve vlákna zapíšu do paralelného poľa, jedno z nich vyhrá a druhé podľa toho prehrá a vy neviete, ktoré z nich je ktoré. Ak nie sú volatilné, potom môže byť poradie ľubovoľné – a funguje to naozaj dobre. Ľudia sa skutočne starajú o poradie operácií, umiestňujú volatile na správne miesta a na správnych miestach očakávajú problémy s výkonom súvisiace s pamäťou. Inak by jednoducho napísali kód vo forme slučiek od 1 do N, kde N je niekoľko biliónov, v nádeji, že všetky zložité prípady sa automaticky stanú paralelnými – a tam to nefunguje. Ale v H2O to nie je ani Java, ani Scala; ak chcete, môžete to považovať za „Java mínus mínus“. Toto je veľmi jasný štýl programovania a je podobný písaniu jednoduchého kódu C alebo Java so slučkami a poľami. Zároveň však môže byť pamäť spracovaná v terabajtoch. Stále používam H2O. Z času na čas ho používam v rôznych projektoch – a stále je to najrýchlejšia vec, niekoľkonásobne rýchlejšia ako jej konkurenti. Ak robíte veľké dáta so stĺpcovými dátami, je veľmi ťažké poraziť H2O.

Technické výzvy

Andrew: Čo bolo vašou najväčšou výzvou počas celej kariéry?

Cliff: Diskutujeme o technickej alebo netechnickej časti problému? Povedal by som, že najväčšie výzvy nie sú technické. 
Čo sa týka technických výziev. Jednoducho som ich porazil. Ani neviem, čo bolo najväčšie, ale bolo tam niekoľko celkom zaujímavých, ktoré zabrali dosť času, duševný boj. Keď som išiel do Sunu, bol som si istý, že urobím rýchly kompilátor a hŕba starších mi na to odpovedala, že sa mi to nikdy nepodarí. Ale išiel som touto cestou, napísal som kompilátor do alokátora registrov a bolo to celkom rýchle. Bolo to také rýchle ako moderné C1, ale alokátor bol vtedy oveľa pomalší a pri spätnom pohľade to bol veľký problém s dátovou štruktúrou. Potreboval som to na napísanie grafického alokátora registrov a nerozumel som dileme medzi expresivitou kódu a rýchlosťou, ktorá v tej dobe existovala a bola veľmi dôležitá. Ukázalo sa, že dátová štruktúra zvyčajne presahuje veľkosť vyrovnávacej pamäte na x86 tej doby, a preto, ak som pôvodne predpokladal, že alokátor registrov bude pracovať 5-10 percent z celkového času jitteru, v skutočnosti sa ukázalo, že 50 percent.

Postupom času sa kompilátor stal čistejším a efektívnejším, vo viacerých prípadoch prestal generovať strašný kód a výkon sa začal čoraz viac podobať tomu, čo produkuje kompilátor C. Ak, samozrejme, nenapíšete nejaké kraviny, ktoré ani C nezrýchli . Ak napíšete kód ako C, získate výkon ako C vo viacerých prípadoch. A čím ďalej, tým častejšie ste dostávali kód, ktorý sa asymptoticky zhodoval s úrovňou C, alokátor registrov začal vyzerať ako niečo úplné... bez ohľadu na to, či váš kód beží rýchlo alebo pomaly. Pokračoval som v práci na alokátore, aby urobil lepšie výbery. Stal sa čoraz pomalším, no podával čoraz lepší výkon v prípadoch, s ktorými si nikto iný neporadil. Mohol by som sa ponoriť do alokátora registrov, pochovať tam mesiac práce a zrazu by sa celý kód začal vykonávať o 5% rýchlejšie. Stalo sa to znova a znova a z prideľovača registrov sa stalo niečo ako umelecké dielo - každý ho miloval alebo nenávidel a ľudia z akadémie sa pýtali na tému „prečo sa všetko robí takto“, prečo nie riadkové skenovaniea aky je v tom rozdiel. Odpoveď je stále rovnaká: alokátor založený na farbení grafu plus veľmi starostlivá práca s kódom vyrovnávacej pamäte sa rovná víťaznej zbrani, najlepšej kombinácii, ktorú nikto nemôže poraziť. A to je dosť nezrejmá vec. Všetko ostatné, čo tam kompilátor robí, sú pomerne dobre naštudované veci, aj keď sa tiež dostali na úroveň umenia. Vždy som robil veci, ktoré mali z kompilátora urobiť umelecké dielo. Ale nič z toho nebolo nič mimoriadne – až na prideľovač registrov. Trik je byť opatrný vyrúbať pod záťažou a ak sa to stane (v prípade záujmu môžem vysvetliť podrobnejšie), znamená to, že môžete inline inline agresívnejšie, bez rizika, že prepadnete zlom v harmonograme výkonu. V tých časoch existovala partia kompilátorov v plnom rozsahu, ovešaných čačky a píšťalky, ktoré mali alokátory registrov, ale nikto iný to nedokázal.

Problém je v tom, že ak pridáte metódy, ktoré podliehajú inliningu, zväčšíte a zväčšíte inlining area, množina použitých hodnôt okamžite prevýši počet registrov a musíte ich orezať. Kritická úroveň zvyčajne prichádza, keď sa alokátor vzdá a jeden dobrý kandidát na únik stojí za iného, ​​predáte nejaké všeobecne divoké veci. Hodnota inliningu je v tom, že prídete o časť réžie, réžie na volanie a ukladanie, hodnoty vidíte vo vnútri a môžete ich ďalej optimalizovať. Náklady na inlining spočívajú v tom, že sa vytvorí veľké množstvo živých hodnôt, a ak váš alokátor registrov zhorí viac, ako je potrebné, okamžite prehráte. Väčšina alokátorov má preto problém: keď inlining prekročí určitú hranicu, všetko na svete sa začne rúbať a produktivita sa dá spláchnuť do záchoda. Tí, ktorí implementujú kompilátor, pridávajú určitú heuristiku: napríklad zastaviť vkladanie, počnúc nejakou dostatočne veľkou veľkosťou, pretože alokácie všetko zničia. Takto sa tvorí zlom v grafe výkonnosti – inline, inline, výkon pomaly rastie – a potom bum! – spadne ako rýchly zdvihák, pretože si priveľa lemoval. Takto fungovalo všetko pred príchodom Javy. Java vyžaduje oveľa viac inliningu, takže som musel urobiť môj alokátor oveľa agresívnejším, aby sa skôr vyrovnal ako zrútil, a ak ho vložíte príliš veľa, začne sa rozlievať, ale potom stále prichádza chvíľa „už sa nesype“. Toto je zaujímavý postreh a len mi z ničoho nič prišiel, nie je očividný, ale oplatilo sa. Ujal som sa agresívneho inliningu a zaviedlo ma to na miesta, kde výkon Java a C fungujú vedľa seba. Sú si naozaj blízki – dokážem napísať kód Java, ktorý je výrazne rýchlejší ako kód C a podobné veci, ale v priemere sú v celkovom obraze vecí zhruba porovnateľné. Myslím, že súčasťou tejto zásluhy je alokátor registrov, ktorý mi umožňuje inline čo najhlúpejšie. Jednoducho vložím všetko, čo vidím. Tu je otázka, či alokátor funguje dobre, či je výsledkom inteligentne fungujúci kód. Bola to veľká výzva: pochopiť toto všetko a zabezpečiť, aby to fungovalo.

Trochu o prideľovaní registrov a viacjadrách

Vladimir: Problémy ako prideľovanie registrov sa zdajú byť akousi večnou, nekonečnou témou. Zaujímalo by ma, či niekedy existoval nápad, ktorý vyzeral sľubne a potom v praxi zlyhal?

Cliff: Určite! Pridelenie registra je oblasť, v ktorej sa pokúšate nájsť nejakú heuristiku na vyriešenie NP-úplného problému. A nikdy nemôžete dosiahnuť dokonalé riešenie, však? To je jednoducho nemožné. Pozrite, kompilácia Ahead of Time - tiež funguje zle. Konverzácia tu je o niektorých priemerných prípadoch. O typickom výkone, takže môžete ísť a merať niečo, o čom si myslíte, že je dobrý typický výkon – koniec koncov pracujete na jeho zlepšení! Prideľovanie registrov je téma o výkonnosti. Keď máte prvý prototyp, funguje a namaľuje, čo treba, začína sa výkonová práca. Treba sa naučiť dobre merať. Prečo je to dôležité? Ak máte jasné údaje, môžete sa pozrieť na rôzne oblasti a uvidíte: áno, tu to pomohlo, ale tam sa všetko zlomilo! Objaví sa niekoľko dobrých nápadov, pridáte nové heuristiky a zrazu všetko začne fungovať v priemere o niečo lepšie. Alebo sa nespustí. Mal som veľa prípadov, keď sme bojovali o päťpercentný výkon, ktorý odlišoval náš vývoj od predchádzajúceho alokátora. A zakaždým to vyzerá takto: niekde vyhráte, niekde prehráte. Ak máte dobré nástroje na analýzu výkonu, môžete nájsť stratené nápady a pochopiť, prečo zlyhávajú. Možno stojí za to nechať všetko tak, alebo možno pristupovať k dolaďovaniu serióznejšie alebo ísť von a opraviť niečo iné. Je to celá kopa vecí! Urobil som tento skvelý hack, ale potrebujem aj tento a tento a tento - a ich celková kombinácia prináša určité vylepšenia. A samotári môžu zlyhať. Toto je povaha výkonovej práce na NP-úplných problémoch.

Vladimir: Človek má pocit, že veci ako maľovanie v alokátoroch sú už vyriešený problém. Nuž, je to rozhodnuté za vás, súdiac podľa toho, čo hovoríte, či to potom vôbec stojí za to...

Cliff: Nie je to vyriešené ako také. Ste to vy, kto to musí zmeniť na „vyriešené“. Sú tu ťažké problémy a treba ich riešiť. Akonáhle je toto hotové, je čas pracovať na produktivite. Podľa toho musíte k tejto práci pristupovať – robiť benchmarky, zbierať metriky, vysvetľovať situácie, keď po návrate k predchádzajúcej verzii váš starý hack opäť začal fungovať (alebo naopak prestal). A nevzdávajte sa, kým niečo nedosiahnete. Ako som už povedal, ak existujú skvelé nápady, ktoré nefungovali, ale v oblasti prideľovania registrov nápadov je to približne nekonečné. Môžete si napríklad prečítať vedecké publikácie. Aj keď teraz sa táto oblasť začala pohybovať oveľa pomalšie a stala sa jasnejšou ako v mladosti. V tejto oblasti však pracuje nespočetné množstvo ľudí a všetky ich nápady stoja za vyskúšanie, všetci čakajú v krídlach. A nemôžete povedať, aké sú dobré, pokiaľ ich nevyskúšate. Ako dobre sa integrujú so všetkým ostatným vo vašom alokátore, pretože alokátor robí veľa vecí a niektoré nápady nebudú fungovať vo vašom konkrétnom alokátore, ale v inom alokátore budú ľahko fungovať. Hlavným spôsobom, ako vyhrať pre alokátora, je vytiahnuť pomalé veci mimo hlavnej cesty a prinútiť ich, aby sa rozdelili pozdĺž hraníc pomalých ciest. Takže ak chcete spustiť GC, choďte na pomalú cestu, deoptimalizujte, vyhoďte výnimku, všetky tieto veci - viete, že tieto veci sú relatívne zriedkavé. A sú naozaj zriedkavé, overil som si to. Robíte prácu navyše a odstraňuje to veľa obmedzení na týchto pomalých cestách, ale na tom vlastne nezáleží, pretože sú pomalé a málokedy sa po nich cestuje. Napríklad nulový ukazovateľ - to sa nikdy nestane, však? Musíte mať niekoľko ciest na rôzne veci, ale nemali by zasahovať do hlavnej. 

Vladimir: Čo si myslíš o viacjadrách, keď sú tam tisíce jadier naraz? Je to užitočná vec?

Cliff: Úspech GPU ukazuje, že je celkom užitočný!

Vladimir: Sú dosť špecializovaní. A čo procesory na všeobecné použitie?

Cliff: No, to bol Azulov obchodný model. Odpoveď prišla v ére, keď ľudia skutočne milovali predvídateľný výkon. Vtedy bolo ťažké napísať paralelný kód. Model kódovania H2O je vysoko škálovateľný, ale nejde o model na všeobecné použitie. Možno trochu všeobecnejšie ako pri použití GPU. Hovoríme o zložitosti vývoja takejto veci alebo o zložitosti jej používania? Napríklad Azul ma naučil zaujímavú lekciu, dosť nezrejmú: malé kešky sú normálne. 

Najväčšia výzva v živote

Vladimir: A čo netechnické výzvy?

Cliff: Najväčšou výzvou bolo nebyť... láskavý a milý k ľuďom. A v dôsledku toho som sa neustále ocitol v mimoriadne konfliktných situáciách. Tie, o ktorých som vedel, že sa veci pokazia, ale nevedel som, ako sa s týmito problémami pohnúť vpred a nevedel som ich zvládnuť. Vznikli tak mnohé dlhodobé problémy, trvajúce desaťročia. Skutočnosť, že Java má kompilátory C1 a C2, je toho priamym dôsledkom. Priamym dôsledkom je aj fakt, že v Jave desať rokov po sebe neexistovala viacúrovňová kompilácia. Je zrejmé, že sme takýto systém potrebovali, ale nie je zrejmé, prečo neexistoval. Mal som problémy s jedným inžinierom... alebo skupinou inžinierov. Kedysi, keď som začal pracovať v Sun, bol som... Dobre, nielen vtedy, vo všeobecnosti mám vždy na všetko svoj vlastný názor. A myslel som si, že je to pravda, že by si si mohol vziať túto svoju pravdu a povedať ju bezhlavo. Najmä preto, že som mal väčšinu času šokujúco pravdu. A ak sa vám tento prístup nepáči... najmä ak sa zjavne mýlite a robíte nezmysly... Vo všeobecnosti by túto formu komunikácie toleroval málokto. Aj keď niektorí by mohli, ako ja. Celý svoj život som postavil na meritokratických princípoch. Ak mi ukážete niečo zlé, okamžite sa otočím a poviem: povedal si nezmysel. Zároveň sa, samozrejme, ospravedlňujem a to všetko si všimnem, ak nejaké sú, a podniknem ďalšie správne kroky. Na druhej strane mám šokujúco pravdu o šokujúco veľkom percente celkového času. A vo vzťahoch s ľuďmi to veľmi nefunguje. Nesnažím sa byť milý, ale kladiem otázku otvorene. "Toto nikdy nebude fungovať, pretože raz, dva a tri." A oni povedali: "Ach!" Boli tu aj ďalšie dôsledky, ktoré bolo asi lepšie ignorovať: napríklad tie, ktoré viedli k rozvodu s mojou ženou a k desaťročným depresiám po tom.

Výzva je boj s ľuďmi, s ich vnímaním toho, čo môžete alebo nemôžete robiť, čo je dôležité a čo nie. V súvislosti so štýlom kódovania bolo veľa problémov. Stále píšem veľa kódu a v tých časoch som dokonca musel spomaliť, pretože som robil príliš veľa paralelných úloh a robil som ich zle, namiesto toho, aby som sa sústredil na jednu. Pri pohľade späť som napísal polovicu kódu pre príkaz Java JIT, príkaz C2. Ďalší najrýchlejší kódovač písal o polovicu pomalšie, ďalší o polovicu pomalšie a bol to exponenciálny pokles. Siedma osoba v tomto rade bola veľmi, veľmi pomalá - to sa stáva vždy! Dotkol som sa veľkého množstva kódu. Pozrel som sa na to, kto čo napísal, bez výnimky som zízal na ich kód, recenzoval som každý z nich a stále som písal viac sám ako ktokoľvek z nich. Tento prístup u ľudí veľmi nefunguje. Niektorým sa to nepáči. A keď si s tým nevedia rady, začnú sa všelijaké sťažnosti. Napríklad mi raz povedali, aby som prestal kódovať, pretože som písal príliš veľa kódu a ohrozovalo to tím, a všetko mi to znelo ako vtip: kámo, ak zvyšok tímu zmizne a ja budem pokračovať v písaní kódu, ty stratím iba polovicu tímov. Na druhej strane, ak budem pokračovať v písaní kódu a vy stratíte polovicu tímu, znie to ako veľmi zlý manažment. Nikdy som o tom veľmi nepremýšľal, nikdy som o tom nehovoril, ale stále to bolo niekde v mojej hlave. Vzadu mi hlavou kolovala myšlienka: "Robíte si zo mňa všetci srandu?" Takže najväčší problém som mal ja a moje vzťahy s ľuďmi. Teraz si rozumiem oveľa lepšie, dlho som viedol tím programátorov a teraz ľuďom priamo hovorím: viete, som, kto som, a budete sa musieť so mnou vysporiadať - je to v poriadku, ak budem stáť? tu? A keď to začali riešiť, všetko fungovalo. V skutočnosti nie som ani zlý, ani dobrý, nemám žiadne zlé úmysly ani sebecké túžby, je to len moja podstata a musím s tým nejako žiť.

Andrew: Len nedávno všetci začali hovoriť o sebauvedomení pre introvertov a o mäkkých zručnostiach vo všeobecnosti. Čo na to poviete?

Cliff: Áno, to bol poznatok a lekcia, ktorú som si odniesol z rozvodu s manželkou. To, čo som sa naučil z rozvodu, bolo pochopenie samej seba. Takto som začal chápať iných ľudí. Pochopte, ako táto interakcia funguje. To viedlo k objavom jeden po druhom. Došlo k uvedomeniu si toho, kto som a čo predstavujem. Čo robím: buď som zaujatý úlohou, alebo sa vyhýbam konfliktom, alebo niečomu inému – a táto úroveň sebauvedomenia skutočne pomáha udržať sa pod kontrolou. Potom ide všetko oveľa jednoduchšie. Jedna vec, ktorú som objavil nielen u seba, ale aj u iných programátorov, je neschopnosť verbalizovať myšlienky, keď ste v stave emočného stresu. Napríklad tam sedíte, kódujete, v stave prúdenia, a potom k vám pribehnú a začnú hystericky kričať, že niečo je zlomené a teraz budú proti vám prijaté extrémne opatrenia. A nemôžete povedať ani slovo, pretože ste v stave emocionálneho stresu. Získané vedomosti vám umožňujú pripraviť sa na túto chvíľu, prežiť ju a prejsť na ústupový plán, po ktorom môžete niečo urobiť. Takže áno, keď si začnete uvedomovať, ako to všetko funguje, je to obrovská životná udalosť. 
Sám som nevedel nájsť tie správne slová, ale pamätal som si postupnosť akcií. Ide o to, že táto reakcia je rovnako fyzická ako verbálna a potrebujete priestor. Taký priestor v zenovom zmysle. To je presne to, čo je potrebné vysvetliť a potom okamžite ustúpiť - čisto fyzicky odstúpiť. Keď mlčím slovne, dokážem emocionálne spracovať situáciu. Keď sa adrenalín dostane do vášho mozgu, prepne vás do režimu boja alebo úteku, nemôžete už nič povedať, nie - teraz ste idiot, bičujúci inžinier, neschopný slušnej reakcie alebo dokonca zastaviť útok a útočník je voľný útočiť znova a znova. Najprv sa musíte znova stať samým sebou, získať kontrolu, dostať sa z režimu „bojuj alebo uteč“.

A na to potrebujeme verbálny priestor. Len voľné miesto. Ak vôbec niečo poviete, môžete to povedať presne a potom choďte a skutočne nájdite „priestor“ pre seba: choďte na prechádzku do parku, zamknite sa v sprche - na tom nezáleží. Hlavná vec je dočasne sa od tejto situácie odpojiť. Len čo aspoň na pár sekúnd vypnete, kontrola sa vráti, začnete triezvo uvažovať. "Dobre, nie som nejaký idiot, nerobím hlúposti, som celkom užitočný človek." Keď sa vám podarí presvedčiť, je čas prejsť do ďalšej fázy: pochopiť, čo sa stalo. Boli ste napadnutí, útok prišiel z miesta, kde ste ho nečakali, bol to nečestný, odporný útok. Je to zlé. Ďalším krokom je pochopiť, prečo to útočník potreboval. Naozaj, prečo? Možno preto, že on sám je zúrivý? Prečo je naštvaný? Napríklad preto, že sa posral a nevie prijať zodpovednosť? To je spôsob, ako opatrne zvládnuť celú situáciu. To si ale vyžaduje priestor na manévrovanie, verbálny priestor. Úplne prvým krokom je prerušenie verbálneho kontaktu. Vyhnite sa diskusii so slovami. Zrušte to, odíďte čo najrýchlejšie. Ak je to telefonický rozhovor, stačí zavesiť – toto je zručnosť, ktorú som sa naučil pri komunikácii s bývalou manželkou. Ak sa konverzácia nevyvíja dobre, povedzte „zbohom“ a zaveste. Z druhej strany telefónu: „bla bla bla“, odpoviete: „áno, čau!“ a zavesiť. Stačí ukončiť konverzáciu. O päť minút neskôr, keď sa k vám vráti schopnosť rozumne myslieť, trochu ste vychladli, je možné premýšľať o všetkom, čo sa stalo a čo bude ďalej. A začnite formulovať premyslenú odpoveď, nie len reagovať z emócií. Prelomom v sebauvedomení bol pre mňa práve fakt, že v prípade emočného stresu nemôžem rozprávať. Dostať sa z tohto stavu, premýšľať a plánovať, ako reagovať a kompenzovať problémy - to sú správne kroky v prípade, keď nemôžete hovoriť. Najjednoduchšie je utiecť zo situácie, v ktorej sa prejavuje emočný stres a jednoducho sa na tomto strese prestať podieľať. Potom sa stanete schopným myslieť, keď dokážete myslieť, stanete sa schopnými hovoriť atď.

Mimochodom, na súde sa vám to snaží urobiť protichodný právnik - teraz je jasné prečo. Pretože má schopnosť potlačiť ťa do takého stavu, že nevieš napríklad ani vysloviť svoje meno. Vo veľmi skutočnom zmysle nebudete môcť hovoriť. Ak sa vám to stane a ak viete, že sa ocitnete na mieste, kde zúria slovné bitky, na mieste, akým je súd, potom môžete prísť so svojím právnikom. Právnik sa vás zastane a zastaví verbálny útok a urobí to úplne legálnym spôsobom a stratený zenový priestor sa vám vráti. Napríklad som musel niekoľkokrát zavolať svojej rodine, sudca bol v tejto veci celkom priateľský, ale protichodný právnik na mňa kričal a kričal, nemohol som ani dostať slovo. V týchto prípadoch mi najlepšie vychádza použitie mediátora. Sprostredkovateľ zastaví všetok tento tlak, ktorý sa na vás valí v nepretržitom prúde, nájdete potrebný zenový priestor a s ním sa vracia schopnosť hovoriť. Toto je celá oblasť vedomostí, v ktorej je veľa čo študovať, veľa objavovať v sebe a to všetko sa mení na strategické rozhodnutia na vysokej úrovni, ktoré sú pre rôznych ľudí rôzne. Niektorí ľudia nemajú vyššie opísané problémy, zvyčajne ich nemajú ľudia, ktorí sú profesionálni predajcovia. Všetci títo ľudia, ktorí sa živia slovom – slávni speváci, básnici, náboženskí vodcovia a politici, majú vždy čo povedať. Oni také problémy nemajú, ale ja áno.

Andrew: Bolo to... neočakávané. Skvelé, už sme toho veľa nahovorili a je čas tento rozhovor ukončiť. Na konferencii sa určite stretneme a budeme môcť v tomto dialógu pokračovať. Vidíme sa na Hydre!

V rozhovore s Cliffom môžete pokračovať na konferencii Hydra 2019, ktorá sa bude konať 11. – 12. júla 2019 v Petrohrade. Príde so správou „Zážitok z hardvérovej transakčnej pamäte Azul“. Lístky je možné zakúpiť na oficiálnej webovej stránke.

Zdroj: hab.com

Pridať komentár