Skvělý rozhovor s Cliffem Clickem, otcem kompilace JIT v Javě

Skvělý rozhovor s Cliffem Clickem, otcem kompilace JIT v JavěCliff Click — CTO Cratus (IoT senzory pro zlepšování procesů), zakladatel a spoluzakladatel několika startupů (včetně Rocket Realtime School, Neurensic a H2O.ai) s několika úspěšnými výstupy. Cliff napsal svůj první kompilátor ve věku 15 let (Pascal pro TRS Z-80)! Nejznámější je jeho práce na C2 v Javě (The Sea of ​​​​Nodes IR). Tento kompilátor ukázal světu, že JIT dokáže produkovat vysoce kvalitní kód, což byl jeden z faktorů vzniku Javy jako jedné z hlavních moderních softwarových platforem. Poté Cliff pomohl Azul Systems postavit 864jádrový sálový počítač s čistě Java softwarem, který podporoval GC pauzy na 500gigabajtové hromadě během 10 milisekund. Obecně se Cliffovi podařilo zapracovat na všech aspektech JVM.

 
Tento habrapost je skvělý rozhovor s Cliffem. Budeme mluvit o následujících tématech:

  • Přechod na nízkoúrovňové optimalizace
  • Jak udělat velký refaktoring
  • Nákladový model
  • Nízkoúrovňové optimalizační školení
  • Praktické příklady zlepšení výkonu
  • Proč si vytvářet vlastní programovací jazyk
  • Kariéra výkonového inženýra
  • Technické výzvy
  • Něco málo o alokaci registrů a vícejádrech
  • Největší výzva v životě

Rozhovor vede:

  • Andrej Satarin z webových služeb Amazon. Ve své kariéře stihl pracovat ve zcela odlišných projektech: otestoval distribuovanou databázi NewSQL v Yandexu, cloudový detekční systém v Kaspersky Lab, hru pro více hráčů na Mail.ru a službu pro výpočet devizových cen v Deutsche Bank. Zájem o testování rozsáhlých backendových a distribuovaných systémů.
  • Vladimír Sitnikov z Netcrackeru. Deset let práce na výkonu a škálovatelnosti NetCracker OS, softwaru používaného telekomunikačními operátory k automatizaci procesů správy sítí a síťových zařízení. Zajímám se o problémy s výkonem Java a Oracle Database. Autor více než tuctu vylepšení výkonu v oficiálním ovladači PostgreSQL JDBC.

Přechod na nízkoúrovňové optimalizace

Andrew: Jste velké jméno ve světě kompilace JIT, Javy a práce s výkonem obecně, že? 

Útes: Je to tak!

Andrew: Začněme několika obecnými otázkami o výkonové práci. Co si myslíte o volbě mezi optimalizací na vysoké a nízké úrovni, jako je práce na úrovni CPU?

Útes: Ano, vše je zde jednoduché. Nejrychlejší kód je ten, který se nikdy nespustí. Proto vždy musíte začít od vysoké úrovně, pracovat na algoritmech. Lepší zápis O porazí horší zápis O, pokud nezasáhnou nějaké dostatečně velké konstanty. Věci nízké úrovně jsou poslední. Obvykle, pokud jste dostatečně dobře optimalizovali zbytek svého stacku a stále vám zbývají nějaké zajímavé věci, je to nízká úroveň. Jak ale začít od vysoké úrovně? Jak víte, že bylo odvedeno dost práce na vysoké úrovni? No... v žádném případě. Neexistují žádné hotové recepty. Musíte problému porozumět, rozhodnout se, co budete dělat (abyste v budoucnu nedělali zbytečné kroky) a poté můžete odhalit profilovač, který může říct něco užitečného. V určitém okamžiku si sami uvědomíte, že jste se zbavili nepotřebných věcí a je čas udělat nějaké jemné doladění na nízké úrovni. To je rozhodně zvláštní druh umění. Mnoho lidí dělá zbytečné věci, ale pohybují se tak rychle, že nemají čas starat se o produktivitu. Ale to je až do té doby, než otázka vyvstane otevřeně. Obvykle 99 % času nikoho nezajímá, co dělám, až do okamžiku, kdy na kritické cestě přijde důležitá věc, o kterou se nikdo nestará. A tady vám všichni začnou nadávat, „proč to od samého začátku nefungovalo dokonale“. Obecně platí, že ve výkonu je vždy co zlepšovat. Ale v 99 % případů nemáte žádné potenciální zákazníky! Jen se snažíte, aby něco fungovalo, a během toho zjistíte, co je důležité. Nikdy nemůžete dopředu vědět, že tento kousek musí být dokonalý, takže vlastně musíte být perfektní ve všem. Ale to je nemožné a vy to neděláte. Vždy je třeba spoustu věcí opravit – a to je zcela normální.

Jak udělat velký refaktoring

Andrew: Jak pracujete na představení? Toto je průřezový problém. Museli jste například někdy pracovat na problémech, které vznikají průnikem mnoha existujících funkcí?

Útes: Snažím se tomu vyhýbat. Pokud vím, že výkon bude problém, přemýšlím o tom, než začnu kódovat, zejména s datovými strukturami. To vše ale často zjistíte až později. A pak musíte jít do extrémních opatření a udělat to, čemu říkám „přepsat a dobýt“: musíte chytit dostatečně velký kus. Část kódu bude muset být stále přepsána kvůli problémům s výkonem nebo něčemu jinému. Ať už je důvod přepisování kódu jakýkoli, téměř vždy je lepší přepsat větší část než menší část. V tuto chvíli se všichni začnou třást strachem: "Ó můj bože, nemůžete sáhnout na tolik kódu!" Ale ve skutečnosti tento přístup téměř vždy funguje mnohem lépe. Musíte se okamžitě chopit velkého problému, nakreslit kolem něj velký kruh a říct: Přepíšu všechno uvnitř kruhu. Ohraničení je mnohem menší než obsah uvnitř, který je třeba vyměnit. A pokud vám takové vytyčení hranic umožní dělat práci uvnitř perfektně, máte volné ruce, dělejte si, co chcete. Jakmile problém pochopíte, proces přepisování je mnohem jednodušší, takže si to pořádně kousněte!
Zároveň, když uděláte velký přepis a uvědomíte si, že výkon bude problém, můžete se o to okamžitě začít starat. Obvykle se to změní v jednoduché věci, jako je „nekopírujte data, spravujte data co nejjednodušeji, zmenšete je“. Při velkých přepisech existují standardní způsoby, jak zlepšit výkon. A téměř vždy se točí kolem dat.

Nákladový model

Andrew: V jednom z podcastů jste mluvil o nákladových modelech v kontextu produktivity. Můžete vysvětlit, co jste tím myslel?

Útes: Rozhodně. Narodil jsem se v době, kdy byl výkon procesoru extrémně důležitý. A tato éra se znovu vrací – osud není bez ironie. Začal jsem žít v dobách osmibitových strojů, můj první počítač pracoval s 256 bajty. Přesně bajtů. Všechno bylo velmi malé. Instrukce se musely počítat, a jak jsme se začali posouvat nahoru v zásobníku programovacích jazyků, jazyky nabíraly víc a víc. Byl tam Assembler, pak Basic, pak C a C se staralo o spoustu detailů, jako je alokace registrů a výběr instrukcí. Ale tam bylo všechno docela jasné, a kdybych udělal ukazatel na instanci proměnné, pak bych dostal load a cena této instrukce je známá. Hardware produkuje určitý počet strojových cyklů, takže rychlost provádění různých věcí lze vypočítat jednoduše sečtením všech instrukcí, které se chystáte spustit. Každé porovnání/test/pobočka/volání/načtení/obchod lze sečíst a říci: to je doba provedení pro vás. Při práci na zlepšení výkonu si určitě dáte pozor na to, jaká čísla odpovídají malým horkým cyklům. 
Jakmile ale přejdete na Javu, Python a podobné věci, velmi rychle se vzdálíte od nízkoúrovňového hardwaru. Kolik stojí volání getteru v Javě? Pokud je JIT v HotSpotu správný vložené, načte se, ale pokud to neudělá, bude to volání funkce. Protože volání probíhá v horké smyčce, přepíše všechny ostatní optimalizace v této smyčce. Reálné náklady proto budou mnohem vyšší. A okamžitě ztratíte možnost podívat se na kus kódu a pochopit, že bychom ho měli spustit z hlediska taktu procesoru, paměti a použité mezipaměti. To vše se stane zajímavým, pouze pokud se do představení opravdu pustíte.
Nyní jsme se ocitli v situaci, kdy se rychlost procesoru za posledních deset let téměř nezvýšila. Staré časy jsou zpět! Už nemůžete počítat s dobrým jednovláknovým výkonem. Ale pokud se najednou dostanete do paralelního počítání, je to neuvěřitelně obtížné, všichni na vás koukají jako na Jamese Bonda. Desetinásobné zrychlení zde většinou nastává v místech, kde někdo něco pokazil. Souběh vyžaduje hodně práce. Chcete-li dosáhnout XNUMXx zrychlení, musíte pochopit nákladový model. Co a kolik to stojí? A abyste to mohli udělat, musíte pochopit, jak jazyk sedí na základním hardwaru.
Martin Thompson zvolil pro svůj blog skvělé slovo Mechanická sympatie! Musíte porozumět tomu, co bude hardware dělat, jak přesně to bude dělat a proč vůbec dělá to, co dělá. Pomocí toho je poměrně snadné začít počítat instrukce a zjišťovat, kam jde doba provedení. Pokud nemáte odpovídající výcvik, hledáte jen černou kočku v temné místnosti. Vidím lidi, kteří neustále optimalizují výkon, kteří nemají ponětí, co sakra dělají. Hodně trpí a nedělají velké pokroky. A když vezmu stejný kus kódu, vložím pár malých hacků a dostanu pětinásobné nebo desetinásobné zrychlení, řeknou si: no, to není fér, už jsme věděli, že jste lepší. Úžasný. O čem to mluvím... nákladový model je o tom, jaký kód napíšete a jak rychle to v průměru běží ve velkém.

Andrew: A jak si můžeš v hlavě udržet takový objem? Je toho dosaženo s většími zkušenostmi, nebo? Odkud taková zkušenost pochází?

Útes: No, nezískal jsem své zkušenosti tím nejjednodušším způsobem. Programoval jsem v Assembly v dobách, kdy jste rozuměli každé jednotlivé instrukci. Zní to hloupě, ale od té doby mi instrukční sada Z80 zůstala vždy v hlavě, v paměti. Nepamatuji si jména lidí během minuty hovoru, ale pamatuji si kód napsaný před 40 lety. Je to legrační, vypadá to jako syndrom"idiotský vědec".

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

Andrew: Existuje snadnější způsob, jak se dostat dovnitř?

Útes: Ano i ne. Hardware, který všichni používáme, se v průběhu času tolik nezměnil. Každý používá x86, s výjimkou smartphonů Arm. Pokud neděláte nějaký druh hardcore vkládání, děláte to samé. Dobře, další. Pokyny se také po staletí nezměnily. Musíte jít a něco napsat do Assembly. Ne moc, ale dost na to, abychom tomu začali rozumět. Vy se usmíváte, ale já mluvím zcela vážně. Musíte porozumět korespondenci mezi jazykem a hardwarem. Poté musíte jít a trochu napsat a vytvořit malý překladač hraček pro jazyk malých hraček. Toy-like znamená, že to musí být vyrobeno v rozumném čase. Může to být super jednoduché, ale musí to generovat instrukce. Akt generování instrukce vám pomůže porozumět nákladovému modelu mostu mezi kódem vysoké úrovně, který každý píše, a strojovým kódem, který běží na hardwaru. Tato korespondence bude vypálena do mozku v době psaní kompilátoru. I ten nejjednodušší kompilátor. Poté se můžete začít dívat na Javu a na to, že její sémantická propast je mnohem hlubší a je mnohem obtížnější přes ni stavět mosty. Na Javě je mnohem obtížnější pochopit, zda náš most dopadl dobře nebo špatně, co způsobí jeho rozpad a co ne. Ale potřebujete nějaký výchozí bod, kde se podíváte na kód a pochopíte: "jo, tento getter by měl být vložen pokaždé." A pak se ukáže, že se to někdy stane, kromě situace, kdy se metoda příliš rozroste a JIT začne všechno vkládat. Výkon takových míst lze předvídat okamžitě. Gettery obvykle fungují dobře, ale pak se podíváte na velké horké smyčky a uvědomíte si, že se tam vznášejí nějaká volání funkcí, která nevědí, co dělají. To je problém s rozšířeným používáním getrů, důvodem proč nejsou inline je, že není jasné, zda jsou getry. Pokud máte super malou kódovou základnu, můžete si ji jednoduše zapamatovat a pak říci: toto je getter a toto je setter. Ve velké kódové základně žije každá funkce svou vlastní historií, kterou obecně nikdo nezná. Profiler říká, že jsme na nějaké smyčce ztratili 24 % času a abychom pochopili, co tato smyčka dělá, musíme se podívat na každou funkci uvnitř. Není možné tomu porozumět bez prostudování funkce a to vážně zpomaluje proces porozumění. Proto nepoužívám getry a setry, dostal jsem se na novou úroveň!
Kde získat nákladový model? No, můžete si něco přečíst, samozřejmě... Ale myslím, že nejlepší je jednat. Vytvoření malého kompilátoru bude nejlepší způsob, jak porozumět nákladovému modelu a napasovat jej do vlastní hlavy. Malý překladač, který by se hodil pro programování mikrovlnky, je úkol pro začátečníka. No, myslím, pokud už máte programovací dovednosti, pak by to mělo stačit. Všechny tyto věci, jako je analýza řetězce, který máte jako nějaký druh algebraického výrazu, extrahování pokynů pro matematické operace odtud ve správném pořadí, přebírání správných hodnot z registrů - to vše se děje najednou. A zatímco to uděláte, otiskne se to do vašeho mozku. Myslím, že každý ví, co kompilátor dělá. A to umožní pochopit nákladový model.

Praktické příklady zlepšení výkonu

Andrew: Na co dalšího byste si měli dát pozor při práci na produktivitě?

Útes: Datové struktury. Mimochodem, ano, tyto hodiny jsem už dlouho neučil... Raketová škola. Byla to zábava, ale vyžadovalo to hodně úsilí a já mám taky život! OK. Takže v jedné z velkých a zajímavých tříd „Kam jde váš výkon“ jsem dal studentům příklad: dva a půl gigabajtu fintech dat bylo načteno ze souboru CSV a pak museli vypočítat počet prodaných produktů. . Pravidelné údaje o tickovém trhu. UDP pakety převedené do textového formátu od 70. let. Chicago Mercantile Exchange – nejrůznější věci jako máslo, kukuřice, sójové boby a podobně. Bylo nutné počítat tyto produkty, počet transakcí, průměrný objem pohybu finančních prostředků a zboží atd. Je to docela jednoduchá obchodní matematika: najděte kód produktu (to je 1-2 znaky v hašovací tabulce), získejte částku, přidejte ji do jedné z obchodních sad, přidejte objem, přidejte hodnotu a několik dalších věcí. Velmi jednoduchá matematika. Implementace hračky byla velmi přímočará: vše je v souboru, soubor čtu a pohybuji se v něm, jednotlivé záznamy rozděluji do Java řetězců, hledám v nich potřebné věci a sčítám je podle výše popsané matematiky. A funguje to v nějaké nízké rychlosti.

S tímto přístupem je zřejmé, co se děje, a paralelní výpočty nepomohou, že? Ukazuje se, že pětinásobného zvýšení výkonu lze dosáhnout pouhou volbou správných datových struktur. A to překvapuje i zkušené programátory! V mém konkrétním případě byl trik v tom, že byste neměli přidělovat paměť v horké smyčce. No, to není celá pravda, ale obecně - neměli byste zvýrazňovat „jednou za X“, když je X dostatečně velké. Když má X dva a půl gigabajtu, neměli byste nic přidělovat „jednou na písmeno“, „jednou na řádek“ nebo „jednou na pole“, nic podobného. Tady se tráví čas. Jak to vůbec funguje? Představte si, že volám String.split() nebo BufferedReader.readLine(). Readline vytvoří řetězec ze sady bajtů, které přišly přes síť, jednou pro každý řádek, pro každý ze stovek milionů řádků. Vezmu tento řádek, rozeberu ho a vyhodím. Proč to vyhazuji - no, už jsem to zpracoval, to je vše. Takže pro každý bajt přečtený z těchto 2.7G se do řádku zapíší dva znaky, tedy již 5.4G, a dále je nepotřebuji, takže jsou zahozeny. Když se podíváte na šířku pásma paměti, načteme 2.7G, které projde pamětí a paměťovou sběrnicí v procesoru a pak se dvakrát tolik posílá na linku ležící v paměti a to vše se roztřepe, když se vytvoří každý nový řádek. Ale potřebuji to přečíst, hardware to čte, i když je později všechno roztřepené. A musím to zapsat, protože jsem vytvořil řádek a keše jsou plné - keš nepojme 2.7G. Takže na každý přečtený bajt přečtu další dva bajty a zapíšu další dva bajty a nakonec mají poměr 4:1 - v tomto poměru plýtváme šířkou pásma paměti. A pak se ukáže, že když to udělám String.split() – není to naposled, co to dělám, uvnitř může být dalších 6-7 polí. Takže klasický kód čtení CSV a následné analýzy řetězců plýtvá asi 14:1 šířky pásma paměti, kterou byste skutečně chtěli. Pokud tyto výběry zahodíte, můžete získat pětinásobné zrychlení.

A není to tak těžké. Pokud se podíváte na kód ze správného úhlu, vše se stane docela jednoduchým, jakmile si uvědomíte problém. Neměli byste přestat alokovat paměť úplně: jediný problém je, že něco alokujete a ono to okamžitě zemře a cestou to spálí důležitý zdroj, kterým je v tomto případě šířka pásma paměti. A to vše má za následek pokles produktivity. Na x86 obvykle potřebujete aktivně vypalovat cykly procesoru, ale zde jste spálili veškerou paměť mnohem dříve. Řešením je snížit množství výboje. 
Další část problému spočívá v tom, že pokud spustíte profiler, když dojde paměťový proužek, právě když se to stane, obvykle čekáte, až se mezipaměť vrátí, protože je plná odpadu, který jste právě vyprodukovali, všech těch řádků. Proto se každá operace načítání nebo ukládání zpomalí, protože vedou k vynechání mezipaměti – celá mezipaměť se zpomalila a čeká, až z ní odpadky opustí. Proto bude profiler pouze ukazovat teplý náhodný šum rozmazaný po celé smyčce – v kódu nebude žádná samostatná hot instrukce ani místo. Pouze hluk. A když se podíváte na cykly GC, všechny jsou mladé generace a super rychlé – maximálně mikrosekundy nebo milisekundy. Koneckonců, všechna tato vzpomínka okamžitě zemře. Vy alokujete miliardy gigabajtů a on je řeže, řeže a řeže je znovu. To vše se děje velmi rychle. Ukazuje se, že existují levné cykly GC, teplý hluk po celý cyklus, ale chceme dosáhnout 5x zrychlení. V tuto chvíli by se ve vaší hlavě mělo něco uzavřít a zaznít: "proč to?" Přetečení paměťového pásu se v klasickém ladicím programu nezobrazuje, musíte spustit ladicí program počítadla výkonu hardwaru a podívat se na to sami a přímo. To však nelze přímo podezřívat z těchto tří příznaků. Třetím příznakem je, když se podíváte na to, co zvýrazníte, zeptáte se profilátora a on odpoví: „Udělali jste miliardu řádků, ale GC fungovalo zdarma.“ Jakmile se to stane, uvědomíte si, že jste vytvořili příliš mnoho objektů a spálili celou paměťovou dráhu. Existuje způsob, jak to zjistit, ale není to zřejmé. 

Problém je ve struktuře dat: holá struktura, která je základem všeho, co se děje, je příliš velká, má 2.7G na disku, takže vytváření kopie této věci je velmi nežádoucí - chcete ji okamžitě načíst ze síťové vyrovnávací paměti bajtů do registrů, aby nedošlo k pětinásobnému čtení a zápisu na řádek tam a zpět. Java vám bohužel takovou knihovnu jako součást JDK standardně neposkytuje. Ale to je triviální, ne? V podstatě se jedná o 5-10 řádků kódu, které budou použity k implementaci vašeho vlastního zavaděče řetězců s vyrovnávací pamětí, který opakuje chování třídy řetězců, přičemž je obalem kolem základní vyrovnávací paměti bajtů. Ve výsledku se ukáže, že pracujete skoro jako s řetězci, ale ve skutečnosti se tam ukazatele na vyrovnávací paměť přesouvají a nezpracované bajty se nikam nekopírují, takže se znovu a znovu používají stejné vyrovnávací paměti a operační systém si rád vezme na sebe věci, pro které je určen, jako je skryté dvojité ukládání těchto bajtových vyrovnávacích pamětí do vyrovnávací paměti, a vy se už nebudete prodírat nekonečným proudem zbytečných dat. Mimochodem, chápete, že při práci s GC je zaručeno, že každá alokace paměti nebude pro procesor po posledním cyklu GC vidět? To vše tedy nemůže být v mezipaměti a pak dochází ke 100% zaručenému miss. Při práci s ukazatelem na x86 trvá odečítání registru z paměti 1-2 hodinové cykly, a jakmile k tomu dojde, platíte, platíte, platíte, protože paměť je celá zapnutá. DEVĚT keší – a to jsou náklady na přidělení paměti. Skutečná hodnota.

Jinými slovy, datové struktury se mění nejobtížněji. A jakmile si uvědomíte, že jste zvolili špatnou datovou strukturu, která později zabije výkon, obvykle vás čeká spousta práce, ale pokud to neuděláte, věci se zhorší. V první řadě je potřeba myslet na datové struktury, to je důležité. Hlavní náklady zde připadají na tlusté datové struktury, které se začínají používat ve stylu „zkopíroval jsem datovou strukturu X do datové struktury Y, protože se mi více líbí tvar Y“. Ale operace kopírování (která se zdá být levná) ve skutečnosti plýtvá šířkou pásma paměti a to je místo, kde je všechen promarněný čas provádění pohřben. Pokud mám obrovský řetězec JSON a chci z něj udělat strukturovaný strom DOM POJO nebo tak něco, operace analýzy tohoto řetězce a vytvoření POJO a následného opětovného přístupu k POJO později povede ke zbytečným nákladům – je to není levné. Až na to, že pobíháte kolem POJO mnohem častěji než kolem provázku. Místo toho se můžete pokusit dešifrovat řetězec a extrahovat z něj pouze to, co potřebujete, aniž byste to změnili na POJO. Pokud se toto vše odehrává na cestě, od které je vyžadován maximální výkon, žádné POJO pro vás, je potřeba se do linky nějak přímo přehrabovat.

Proč si vytvářet vlastní programovací jazyk

Andrew: Řekl jste, že abyste pochopili nákladový model, musíte napsat svůj vlastní malý jazyk...

Útes: Ne jazyk, ale kompilátor. Jazyk a kompilátor jsou dvě různé věci. Nejdůležitější rozdíl je ve vaší hlavě. 

Andrew: Mimochodem, pokud vím, tak experimentujete s tvorbou vlastních jazyků. Proč?

Útes: Protože můžu! Jsem v polopenzi, takže je to můj koníček. Celý život implementuji jazyky jiných lidí. Hodně jsem také zapracoval na svém stylu kódování. A také proto, že vidím problémy v jiných jazycích. Vidím, že existují lepší způsoby, jak dělat známé věci. A použil bych je. Už mě nebaví vidět problémy v sobě, v Javě, v Pythonu, v jakémkoli jiném jazyce. React Native, JavaScript a Elm teď píšu jako koníček, který není o důchodu, ale o aktivní práci. Také píšu v Pythonu a s největší pravděpodobností budu pokračovat v práci na strojovém učení pro Java backendy. Existuje mnoho populárních jazyků a všechny mají zajímavé funkce. Každý je dobrý svým vlastním způsobem a můžete se pokusit všechny tyto vlastnosti spojit. Takže studuji věci, které mě zajímají, chování jazyka, snažím se přijít na rozumnou sémantiku. A zatím se mi to daří! Momentálně bojuji se sémantikou paměti, protože to chci mít jako v C a Javě a získat silný model paměti a sémantiku paměti pro zátěže a úložiště. Zároveň mějte automatické odvozování typu jako v Haskellu. Zde se snažím míchat odvození typu typu Haskell s prací s pamětí v C i Javě. To jsem dělal třeba poslední 2-3 měsíce.

Andrew: Pokud vytvoříte jazyk, který přebírá lepší aspekty z jiných jazyků, myslíte si, že někdo udělá opak: vezme vaše nápady a použije je?

Útes: Přesně tak se objevují nové jazyky! Proč je Java podobná C? Protože C mělo dobrou syntaxi, které všichni rozuměli, a Java se touto syntaxí inspirovala, přidali bezpečnost typu, kontrolu hranic polí, GC a také vylepšili některé věci z C. Přidali své vlastní. Ale inspirovali se docela hodně, že? Všichni stojí na ramenou obrů, kteří přišli před vámi – tak se dělá pokrok.

Andrew: Pokud tomu rozumím, váš jazyk bude v bezpečí paměti. Přemýšleli jste o implementaci něčeho jako půjčka od Rust? Podívali jste se na něj, co si o něm myslíte?

Útes: No, psal jsem C celé věky, se vším tím malloc a zdarma a ručně jsem spravoval životnost. Víte, 90-95 % ručně řízené životnosti má stejnou strukturu. A dělat to ručně je velmi, velmi bolestivé. Chtěl bych, aby vám kompilátor jednoduše řekl, co se tam děje a čeho jste svými činy dosáhli. U některých věcí to udělá checker hned po vybalení. A měl by automaticky zobrazovat informace, všemu rozumět a ani mě nezatěžovat předkládáním tohoto pochopení. Musí provést alespoň lokální únikovou analýzu, a pouze pokud selže, musí přidat typové anotace, které budou popisovat životnost – a takové schéma je mnohem složitější než kontrola výpůjček nebo vlastně jakýkoli existující kontrolér paměti. Volba mezi „všechno je v pořádku“ a „ničemu nerozumím“ - ne, musí existovat něco lepšího. 
Takže jako někdo, kdo napsal hodně kódu v C, si myslím, že mít podporu pro automatické řízení životnosti je nejdůležitější věc. Už mě taky štve, jak moc Java využívá paměť a hlavní stížnost je GC. Když alokujete paměť v Javě, nezískáte zpět paměť, která byla lokální při posledním cyklu GC. To není případ jazyků s přesnější správou paměti. Pokud zavoláte malloc, okamžitě získáte paměť, která byla obvykle právě používána. Obvykle uděláte nějaké dočasné věci s pamětí a okamžitě ji vrátíte zpět. A okamžitě se vrátí do bazénu malloc a další cyklus malloc ho znovu vytáhne. Skutečné využití paměti je proto sníženo na množinu živých objektů v daném čase plus úniky. A pokud vše neunikne zcela neslušným způsobem, většina paměti skončí v mezipaměti a procesoru a funguje to rychle. Vyžaduje to ale hodně manuální správy paměti pomocí malloc a volání zdarma ve správném pořadí na správném místě. Rust si s tím dokáže správně poradit sám a v mnoha případech podá ještě lepší výkon, protože spotřeba paměti je zúžena pouze na aktuální výpočet – na rozdíl od čekání na další cyklus GC, aby se paměť uvolnila. Výsledkem je velmi zajímavý způsob, jak zlepšit výkon. A docela výkonný - chci říct, že jsem dělal takové věci při zpracování dat pro fintech, a to mi umožnilo dosáhnout asi pětinásobného zrychlení. To je docela velká podpora, zvláště ve světě, kde procesory nejsou rychlejší a stále čekáme na vylepšení.

Kariéra výkonového inženýra

Andrew: Také bych se rád zeptal na kariéru obecně. Díky své práci JIT v HotSpot jste se dostali na výsluní a poté jste se přestěhovali do Azul, což je také společnost JVM. Ale to už jsme pracovali více na hardwaru než na softwaru. A pak najednou přešli na velká data a strojové učení a pak na odhalování podvodů. Jak se to stalo? To jsou velmi odlišné oblasti vývoje.

Útes: Programuji už docela dlouho a podařilo se mi absolvovat spoustu různých kurzů. A když lidé říkají: „Ach, ty jsi ten, kdo udělal JIT pro Javu!“, je to vždy zábavné. Předtím jsem ale pracoval na klonu PostScriptu – jazyka, který Apple kdysi používal pro své laserové tiskárny. A předtím jsem provedl implementaci jazyka Forth. Myslím, že společným tématem je pro mě vývoj nástrojů. Celý život jsem vyráběl nástroje, pomocí kterých jiní lidé píší své skvělé programy. Podílel jsem se ale také na vývoji operačních systémů, ovladačů, debuggerů na úrovni jádra, jazyků pro vývoj OS, což začalo být triviální, ale postupem času bylo čím dál složitější. Hlavním tématem je ale stále vývoj nástrojů. Velká část mého života prošla mezi Azulem a Sunem a byla o Jávě. Ale když jsem se dostal k Big Data a Machine Learning, nasadil jsem si svůj luxusní klobouk a řekl: „Ach, teď máme netriviální problém a děje se spousta zajímavých věcí a lidé dělají věci.“ Je to skvělá cesta rozvoje.

Ano, opravdu miluji distribuované výpočty. Moje první práce byla jako studentka v C na reklamním projektu. Jednalo se o distribuované výpočty na čipech Zilog Z80, které shromažďovaly data pro analogové OCR, vyrobené skutečným analogovým analyzátorem. Bylo to skvělé a naprosto šílené téma. Ale vyskytly se problémy, některá část nebyla správně rozpoznána, takže jste museli vyjmout obrázek a ukázat jej osobě, která již uměla číst očima a hlásit, co říká, a proto existovaly úlohy s daty a tyto úlohy měli svůj vlastní jazyk. Existoval backend, který toto vše zpracovával – Z80 běžící paralelně s běžícími terminály vt100 – jeden na osobu, a na Z80 byl paralelní programovací model. Nějaký společný kus paměti sdílený všemi Z80 v rámci hvězdné konfigurace; Backplane byla také sdílená a polovina RAM byla sdílena v rámci sítě a další polovina byla soukromá nebo šla do něčeho jiného. Smysluplně komplexní paralelní distribuovaný systém se sdílenou... polosdílenou pamětí. Kdy to bylo... už si ani nepamatuji, někde v polovině 80. let. Docela dávno. 
Ano, předpokládejme, že 30 let je poměrně dlouhá doba. Problémy související s distribuovanými počítači existují poměrně dlouho, lidé jsou již dlouho ve válce s Beowulf- shluky. Takové clustery vypadají jako... Například: existuje Ethernet a k tomuto Ethernetu je připojena vaše rychlá x86 a teď chcete získat falešnou sdílenou paměť, protože distribuované výpočetní kódování tehdy nikdo neuměl, bylo to příliš obtížné a proto tam byla falešná sdílená paměť se stránkami ochranné paměti na x86, a pokud jste napsali na tuto stránku, řekli jsme ostatním procesorům, že pokud přistupují ke stejné sdílené paměti, bude nutné ji načíst od vás, a tedy něco jako protokol pro podporu objevila se koherence mezipaměti a software k tomu. Zajímavý koncept. Skutečným problémem bylo samozřejmě něco jiného. To vše fungovalo, ale rychle jste měli problémy s výkonem, protože nikdo nerozuměl výkonovým modelům na dostatečně dobré úrovni – jaké tam byly vzorce přístupu do paměti, jak zajistit, aby se uzly navzájem donekonečna nepingovaly a tak dále.

V H2O jsem přišel na to, že jsou to samotní vývojáři, kteří jsou zodpovědní za určení, kde je paralelismus skrytý a kde ne. Přišel jsem s modelem kódování, díky kterému bylo psaní vysoce výkonného kódu snadné a jednoduché. Ale psát pomalu běžící kód je těžké, bude to vypadat špatně. Musíte se vážně pokusit napsat pomalý kód, budete muset použít nestandardní metody. Brzdný kód je vidět na první pohled. Výsledkem je, že obvykle píšete kód, který běží rychle, ale musíte vymyslet, co dělat v případě sdílené paměti. To vše je vázáno na velká pole a chování je podobné jako u energeticky nezávislých velkých polí v paralelní Javě. Chci říct, představte si, že dvě vlákna zapisují do paralelního pole, jedno z nich vyhraje a druhé podle toho prohraje a vy nevíte, které je které. Pokud nejsou volatilní, pak může být pořadí, jaké chcete - a to funguje opravdu dobře. Lidé se opravdu starají o pořadí operací, ukládají těkavé na správná místa a očekávají problémy s výkonem související s pamětí na správná místa. Jinak by jednoduše napsali kód ve formě smyček od 1 do N, kde N je několik bilionů, v naději, že všechny složité případy se automaticky stanou paralelními – a tam to nefunguje. Ale v H2O to není ani Java, ani Scala, můžete to považovat za „Java minus“, pokud chcete. Jedná se o velmi jasný styl programování a je podobný psaní jednoduchého kódu C nebo Java se smyčkami a poli. Ale zároveň lze paměť zpracovávat v terabajtech. Stále používám H2O. Čas od času ho používám v různých projektech - a stále je to nejrychlejší, desítkykrát rychlejší než jeho konkurenti. Pokud děláte velká data se sloupcovými daty, je velmi těžké porazit H2O.

Technické výzvy

Andrew: Jaká byla vaše největší výzva za celou vaši kariéru?

Útes: Probíráme technickou nebo netechnickou část problému? Řekl bych, že největší výzvy nejsou technické. 
Co se týče technických výzev. Prostě jsem je porazil. Ani nevím, který byl největší, ale bylo tam několik docela zajímavých, které zabraly docela dost času, duševního boje. Když jsem šel do Sunu, byl jsem si jistý, že udělám rychlý kompilátor, a parta seniorů na to odpověděla, že se mi to nikdy nepodaří. Ale sledoval jsem tuto cestu, napsal kompilátor do alokátoru registrů a bylo to docela rychlé. Bylo to stejně rychlé jako moderní C1, ale alokátor byl tehdy mnohem pomalejší a při zpětném pohledu to byl velký problém datové struktury. Potřeboval jsem to k napsání grafického alokátoru registrů a nerozuměl jsem dilematu mezi expresivitou kódu a rychlostí, které v té době existovalo a bylo velmi důležité. Ukázalo se, že datová struktura na tehdejších x86 obvykle překračuje velikost cache, a proto, pokud jsem zpočátku předpokládal, že alokátor registrů bude pracovat 5-10 procent z celkového času jitteru, ve skutečnosti se ukázalo, že 50 procent.

Jak šel čas, kompilátor se stal čistším a efektivnější, přestal ve více případech generovat hrozný kód a výkon se stále více začal podobat tomu, co produkuje kompilátor C. Pokud ovšem nenapíšete nějakou kravinu, kterou ani C nezrychlí . Pokud napíšete kód jako C, získáte výkon jako C ve více případech. A čím dále, tím častěji jste dostávali kód, který se asymptoticky shodoval s úrovní C, alokátor registrů začal vypadat jako něco kompletního... bez ohledu na to, zda váš kód běží rychle nebo pomalu. Pokračoval jsem v práci na alokátoru, abych dělal lepší výběr. Stal se pomalejším a pomalejším, ale podával lepší a lepší výkon v případech, kdy si nikdo jiný nedokázal poradit. Mohl bych se ponořit do alokátoru registrů, pohřbít tam měsíc práce a najednou by se celý kód začal vykonávat o 5 % rychleji. Stalo se to čas od času a z alokátoru registrů se stalo něco jako umělecké dílo - všichni ho milovali nebo nenáviděli a lidé z akademie se ptali na téma „proč se všechno dělá takhle“, proč ne řádkové skenovánía jaký je v tom rozdíl. Odpověď je stále stejná: alokátor založený na zbarvení grafu plus velmi pečlivá práce s kódem vyrovnávací paměti se rovná vítězné zbrani, nejlepší kombinaci, kterou nikdo nemůže porazit. A to je poněkud nesrozumitelná věc. Všechno ostatní, co tam kompilátor dělá, jsou poměrně dobře nastudované věci, i když byly také dovedeny na úroveň umění. Vždy jsem dělal věci, které měly z kompilátoru udělat umělecké dílo. Nic z toho ale nebylo nic mimořádného – kromě registračního přídělce. Trik je být opatrný uříznout pod zátěží, a pokud k tomu dojde (v případě zájmu mohu vysvětlit podrobněji), znamená to, že můžete inline inline agresivněji, aniž byste riskovali, že se zauzlíte ve výkonovém plánu. V té době existovala parta plnohodnotných kompilátorů, ověšených cetky a píšťalkami, které měly alokátory registrů, ale nikdo jiný to neuměl.

Problém je v tom, že pokud přidáte metody, které podléhají vkládání, zvětšujete a zvětšujete oblast vkládání, sada použitých hodnot okamžitě převyšuje počet registrů a musíte je oříznout. Kritická úroveň obvykle přichází, když to alokátor vzdá, a jeden dobrý kandidát na únik stojí za jiného, ​​prodáte nějaké obecně divoké věci. Hodnota inliningu je v tom, že přijdete o část režie, režie za volání a ukládání, hodnoty vidíte uvnitř a můžete je dále optimalizovat. Cena inliningu spočívá v tom, že se tvoří velké množství živých hodnot, a pokud váš alokátor registrů shoří více, než je nutné, okamžitě prohrajete. Většina alokátorů má proto problém: když inlining překročí určitou hranici, všechno na světě se začne bourat a produktivita se dá spláchnout do záchodu. Ti, kteří implementují kompilátor, přidávají určitou heuristiku: například zastavit vkládání, počínaje nějakou dostatečně velkou velikostí, protože alokace všechno zničí. Takhle se tvoří zlom v grafu výkonu – zařazujete, zařazujete, výkon pomalu roste – a pak bum! – spadne jako rychlý zvedák, protože jste příliš lemovali. Takhle vše fungovalo před příchodem Javy. Java vyžaduje mnohem více inlining, takže jsem musel udělat svůj alokátor mnohem agresivnější, aby se spíše vyrovnal, než aby spadl, a pokud vložíte příliš mnoho, začne se rozlévat, ale pak stále přichází okamžik „no more sypling“. To je zajímavý postřeh a přišel mi jen tak z ničeho nic, neviditelný, ale dobře se vyplatil. Zaujal jsem agresivní inlining a zavedlo mě to do míst, kde vedle sebe fungují Java a C performance. Jsou si opravdu blízcí – dokážu napsat kód Java, který je výrazně rychlejší než kód C a podobné věci, ale v průměru jsou v celkovém pohledu zhruba srovnatelné. Myslím, že součástí této zásluhy je alokátor registru, který mi umožňuje vkládat co nejhloupěji. Prostě vložím všechno, co vidím. Je zde otázka, zda alokátor funguje dobře, zda je výsledkem inteligentně fungující kód. To byla velká výzva: pochopit to všechno a zajistit, aby to fungovalo.

Něco málo o alokaci registrů a vícejádrech

Vladimir: Problémy jako alokace registrů vypadají jako nějaké věčné, nekonečné téma. Zajímalo by mě, jestli někdy existoval nápad, který se zdál slibný a pak v praxi selhal?

Útes: Rozhodně! Alokace registrů je oblast, ve které se snažíte najít nějakou heuristiku k vyřešení NP-úplného problému. A nikdy nemůžete dosáhnout dokonalého řešení, že? To je prostě nemožné. Podívejte se, kompilace Ahead of Time - také funguje špatně. Zdejší rozhovor je o některých průměrných případech. O typickém výkonu, takže můžete jít a měřit něco, o čem si myslíte, že je dobrý typický výkon – koneckonců pracujete na jeho zlepšení! Přidělování registrů je téma o výkonu. Jakmile máte první prototyp, funguje a natírá, co je potřeba, začíná práce na výkonu. Musíte se naučit dobře měřit. Proč je to důležité? Pokud máte jasná data, můžete se podívat na různé oblasti a uvidíte: ano, tady to pomohlo, ale tam se všechno zlomilo! Přijdou nějaké dobré nápady, přidáte nové heuristiky a najednou vše začne fungovat v průměru o něco lépe. Nebo se nespustí. Měl jsem spoustu případů, kdy jsme bojovali o pětiprocentní výkon, který odlišoval náš vývoj od předchozího alokátoru. A pokaždé to vypadá takto: někde vyhrajete, někde prohrajete. Pokud máte dobré nástroje pro analýzu výkonu, můžete najít ztracené nápady a pochopit, proč selhávají. Možná by stálo za to nechat vše tak, jak je, nebo možná přistoupit k doladění seriózněji, nebo jít ven a opravit něco jiného. Je to celá hromada věcí! Udělal jsem tento skvělý hack, ale také potřebuji tento a tento a tento - a jejich celková kombinace dává určitá vylepšení. A samotáři mohou selhat. To je povaha výkonové práce na NP-úplných problémech.

Vladimir: Člověk má pocit, že věci jako malování v alokátorech jsou problém, který už byl vyřešen. Dobře, je to rozhodnuto za vás, soudě podle toho, co říkáte, takže stojí za to...

Útes: Neřeší se to jako takové. Jste to vy, kdo to musí proměnit v „vyřešené“. Existují složité problémy a je třeba je řešit. Jakmile je toto hotovo, je čas pracovat na produktivitě. Podle toho musíte k této práci přistupovat – provádět benchmarky, sbírat metriky, vysvětlovat situace, kdy po návratu k předchozí verzi váš starý hack znovu začal fungovat (nebo naopak přestal). A nevzdávejte se, dokud něčeho nedosáhnete. Jak jsem již řekl, pokud existují skvělé nápady, které nefungovaly, ale v oblasti přidělování registrů nápadů je to přibližně nekonečné. Můžete si například přečíst vědecké publikace. I když nyní se tato oblast začala pohybovat mnohem pomaleji a stala se jasnější než v mládí. V tomto oboru však pracuje nespočet lidí a všechny jejich nápady stojí za vyzkoušení, všichni čekají v křídlech. A nemůžete říct, jak jsou dobré, pokud je nezkusíte. Jak dobře se integrují se vším ostatním ve vašem alokátoru, protože alokátor dělá spoustu věcí a některé nápady ve vašem konkrétním alokátoru nebudou fungovat, ale v jiném alokátoru budou snadno. Hlavním způsobem, jak vyhrát pro alokátora, je vytáhnout pomalé věci mimo hlavní cestu a přinutit je, aby se rozdělily podél hranic pomalých cest. Takže pokud chcete spustit GC, jít pomalou cestou, deoptimalizovat, vyvolat výjimku, všechny ty věci - víte, že tyto věci jsou relativně vzácné. A jsou opravdu vzácné, ověřil jsem si. Uděláte práci navíc a odstraní to spoustu omezení na těchto pomalých cestách, ale na tom vlastně nezáleží, protože jsou pomalé a málokdy se po nich jezdí. Například nulový ukazatel - to se nikdy nestane, že? Musíte mít několik cest pro různé věci, ale neměly by zasahovat do hlavní. 

Vladimir: Co si myslíš o vícejádrech, když jsou tam tisíce jader najednou? Je to užitečná věc?

Útes: Úspěch GPU ukazuje, že je docela užitečný!

Vladimir: Jsou dost specializovaní. A co procesory pro všeobecné použití?

Útes: No, to byl Azulův obchodní model. Odpověď se vrátila v době, kdy lidé opravdu milovali předvídatelný výkon. Tehdy bylo obtížné napsat paralelní kód. Model kódování H2O je vysoce škálovatelný, ale nejedná se o model pro všeobecné použití. Možná trochu obecněji než při použití GPU. Mluvíme o složitosti vývoje takové věci nebo o složitosti jejího použití? Například Azul mi dal zajímavou lekci, která není zcela samozřejmá: malé kešky jsou normální. 

Největší výzva v životě

Vladimir: A co netechnické výzvy?

Útes: Největší výzvou bylo nebýt... ​​laskavý a milý k lidem. A v důsledku toho jsem se neustále dostával do extrémně konfliktních situací. Ty, o kterých jsem věděl, že se věci nedaří, ale nevěděl jsem, jak se s těmi problémy pohnout kupředu a nedokázal jsem je zvládnout. Vzniklo tak mnoho dlouhodobých problémů, trvajících desítky let. Skutečnost, že Java má kompilátory C1 a C2, je toho přímým důsledkem. Přímým důsledkem je i fakt, že deset let po sobě v Javě neexistovala víceúrovňová kompilace. Je zřejmé, že jsme takový systém potřebovali, ale není zřejmé, proč neexistoval. Měl jsem problémy s jedním inženýrem... nebo skupinou inženýrů. Kdysi, když jsem začal pracovat v Sunu, byl jsem... Dobře, nejen tehdy, obecně mám vždy na všechno svůj vlastní názor. A myslel jsem si, že je pravda, že si můžeš vzít tuhle svou pravdu a říct ji bezhlavě. Zvlášť když jsem měl většinu času šokující pravdu. A pokud se vám tento přístup nelíbí... zvláště pokud se evidentně mýlíte a děláte nesmysly... Obecně by tuto formu komunikace snesl málokdo. I když někteří by mohli, jako já. Celý svůj život jsem stavěl na meritokratických principech. Pokud mi ukážete něco špatného, ​​okamžitě se otočím a řeknu: řekl jsi nesmysl. Zároveň se samozřejmě omlouvám a to vše, poznamenám si případné přednosti a podniknu další správná opatření. Na druhou stranu mám otřesně pravdu o šokujícím velkém procentu celkového času. A ve vztazích s lidmi to moc nefunguje. Nesnažím se být milý, ale položím otázku otevřeně. "Tohle nikdy nebude fungovat, protože jedna, dvě a tři." A oni byli jako: "Ach!" Byly tam i další důsledky, které bylo pravděpodobně lepší ignorovat: například ty, které vedly k rozvodu s mou ženou a k deseti letům depresí poté.

Výzva je boj s lidmi, s jejich vnímáním toho, co můžete nebo nemůžete dělat, co je důležité a co ne. Ve stylu kódování bylo mnoho problémů. Stále píšu spoustu kódu a v té době jsem dokonce musel zpomalit, protože jsem dělal příliš mnoho paralelních úkolů a dělal je špatně, místo abych se soustředil na jeden. Když se ohlédnu zpět, napsal jsem polovinu kódu pro příkaz Java JIT, příkaz C2. Další nejrychlejší kodér psal o polovinu pomaleji, další o polovinu pomaleji a došlo k exponenciálnímu poklesu. Sedmá osoba v této řadě byla velmi, velmi pomalá - to se stává vždy! Dotkl jsem se velkého množství kódu. Podíval jsem se na to, kdo co napsal, bez výjimky jsem zíral na jejich kód, zkontroloval jsem každého z nich a stále jsem psal víc sám než kdokoli z nich. Tento přístup u lidí příliš nefunguje. Některým lidem se to nelíbí. A když si s tím neporadí, začínají nejrůznější stížnosti. Jednou mi například řekli, abych přestal kódovat, protože jsem psal příliš mnoho kódu a ohrožovalo to tým, a všechno mi to znělo jako vtip: kámo, pokud zbytek týmu zmizí a já budu dál psát kód, ty ztratím jen polovinu týmů. Na druhou stranu, pokud budu dál psát kód a vy ztratíte polovinu týmu, zní to jako velmi špatné řízení. Nikdy jsem o tom moc nepřemýšlela, nikdy jsem o tom nemluvila, ale pořád to bylo někde v hlavě. Vzadu mi hlavou kolovala myšlenka: "Děláte si ze mě všichni srandu?" Takže největší problém jsem byl já a moje vztahy s lidmi. Nyní si rozumím mnohem lépe, dlouhou dobu jsem byl vedoucím týmu pro programátory a nyní lidem přímo říkám: víte, jsem, kdo jsem, a budete se mnou muset jednat - je to v pořádku, když budu stát? tady? A když to začali řešit, vše fungovalo. Ve skutečnosti nejsem ani zlý, ani dobrý, nemám žádné špatné úmysly ani sobecké touhy, je to jen moje podstata a musím s tím nějak žít.

Andrew: Nedávno všichni začali mluvit o sebeuvědomění pro introverty a obecně o měkkých dovednostech. Co na to říct?

Útes: Ano, to byl poznatek a poučení, které jsem si odnesl z rozvodu s manželkou. Z rozvodu jsem se naučil pochopit sám sebe. Tak jsem začal chápat ostatní lidi. Pochopte, jak tato interakce funguje. To vedlo k objevům jeden za druhým. Bylo tam povědomí o tom, kdo jsem a co zastupuji. Co dělám: buď jsem zaujatý úkolem, nebo se vyhýbám konfliktu, nebo něčemu jinému – a tato úroveň sebeuvědomění skutečně pomáhá udržet se pod kontrolou. Po tomto jde vše mnohem snadněji. Jedna věc, kterou jsem objevil nejen u sebe, ale i u ostatních programátorů, je neschopnost verbalizovat myšlenky, když jste ve stavu emočního stresu. Například tam sedíte a kódujete, ve stavu toku, a pak k vám přiběhnou a začnou hystericky křičet, že je něco rozbité a teď proti vám budou přijata extrémní opatření. A nemůžete říct ani slovo, protože jste ve stavu emočního stresu. Získané znalosti vám umožňují připravit se na tento okamžik, přežít ho a přejít k ústupovému plánu, po kterém můžete něco udělat. Takže ano, když si začnete uvědomovat, jak to všechno funguje, je to obrovská událost, která vám změní život. 
Sám jsem nemohl najít správná slova, ale pamatoval jsem si sled akcí. Jde o to, že tato reakce je stejně fyzická jako verbální a potřebujete prostor. Takový prostor v zenovém smyslu. To je přesně to, co je třeba vysvětlit, a pak okamžitě ustoupit - čistě fyzicky odstoupit. Když mlčím verbálně, dokážu situaci zpracovat emocionálně. Jakmile se adrenalin dostane do vašeho mozku, přepne vás do režimu boje nebo letu, už nemůžete nic říct, ne - teď jste idiot, bičující inženýr, neschopný slušné reakce nebo dokonce zastavení útoku a útočník je volný útočit znovu a znovu. Nejprve se musíte znovu stát sami sebou, znovu získat kontrolu, dostat se z režimu „bojuj nebo uteč“.

A k tomu potřebujeme verbální prostor. Jen volné místo. Pokud vůbec něco řeknete, můžete říct přesně to a pak jít a skutečně najít „prostor“ pro sebe: jít na procházku do parku, zamknout se ve sprše - na tom nezáleží. Hlavní věc je dočasně se od této situace odpojit. Jakmile alespoň na pár sekund vypnete, ovládání se vrátí, začnete střízlivě přemýšlet. "Dobře, nejsem nějaký idiot, nedělám hlouposti, jsem docela užitečný člověk." Jakmile jste byli schopni přesvědčit sami sebe, je čas přejít k další fázi: pochopit, co se stalo. Byli jste napadeni, útok přišel z místa, kde jste ho nečekali, byla to nečestná, odporná léčka. Je to špatné. Dalším krokem je pochopit, proč to útočník potřeboval. Opravdu, proč? Možná proto, že on sám zuří? Proč je naštvaný? Například proto, že se podělal a nedokáže přijmout odpovědnost? To je způsob, jak pečlivě zvládnout celou situaci. To ale vyžaduje prostor pro manévrování, verbální prostor. Úplně prvním krokem je přerušit verbální kontakt. Vyhněte se diskusi se slovy. Zruš to, odejdi co nejrychleji. Pokud je to telefonický rozhovor, stačí zavěsit – to je dovednost, kterou jsem se naučil při komunikaci s bývalou manželkou. Pokud se konverzace nevyvíjí dobře, řekněte „sbohem“ a zavěste. Z druhé strany telefonu: „bla bla bla“, vy odpovídáte: „jo, ahoj!“ a zavěsit. Prostě ukončíte konverzaci. O pět minut později, když se k vám vrátí schopnost rozumně myslet, trochu jste vychladli, je možné přemýšlet o všem, co se stalo a co bude dál. A začněte formulovat promyšlenou odpověď, spíše než jen reagovat z emocí. Pro mě byl průlom v sebeuvědomění právě to, že v případě emočního stresu nemohu mluvit. Dostat se z tohoto stavu, přemýšlet a plánovat, jak reagovat a kompenzovat problémy – to jsou ty správné kroky v případě, kdy nemůžete mluvit. Nejjednodušší je utéct ze situace, ve které se emoční stres projevuje, a prostě se tohoto stresu přestat účastnit. Poté budete schopni myslet, když můžete myslet, stanete se schopni mluvit a tak dále.

Mimochodem, u soudu se vám o to snaží protichůdný právník - nyní je jasné proč. Protože má schopnost vás potlačit do takového stavu, že nedokážete například ani vyslovit své jméno. Ve velmi reálném smyslu nebudete moci mluvit. Pokud se vám to stane a víte, že se ocitnete na místě, kde zuří slovní bitky, na místě jako je soud, pak můžete přijít se svým právníkem. Právník se vás zastane a zastaví verbální útok a udělá to zcela legální cestou a ztracený zenový prostor se vám vrátí. Musel jsem například párkrát volat rodině, soudce se k tomu choval docela přátelsky, ale protilehlý právník na mě křičel a křičel, nemohl jsem se ani zkraje probrat. V těchto případech mi nejlépe vychází použití prostředníka. Prostředník zastaví všechen tento tlak, který se na vás valí v nepřetržitém proudu, najdete potřebný zenový prostor a s ním se vrací schopnost mluvit. Toto je celá oblast vědění, ve které je třeba hodně studovat, hodně objevovat v sobě, a to vše se mění ve strategická rozhodnutí na vysoké úrovni, která se pro různé lidi liší. Někteří lidé výše popsané problémy nemají, obvykle je nemají lidé, kteří jsou profesionálními prodejci. Všichni tito lidé, kteří se živí slovy – slavní zpěváci, básníci, náboženští vůdci i politici, mají vždy co říct. Oni takové problémy nemají, ale já ano.

Andrew: Bylo to... nečekané. Skvělé, už jsme toho hodně namluvili a je čas tento rozhovor ukončit. Určitě se na konferenci sejdeme a budeme moci v tomto dialogu pokračovat. Uvidíme se na Hydra!

V rozhovoru s Cliffem můžete pokračovat na konferenci Hydra 2019, která se bude konat 11. – 12. července 2019 v Petrohradu. Přijde se zprávou „Zážitek z hardwarové transakční paměti Azul“. Vstupenky je možné zakoupit na oficiálních stránkách.

Zdroj: www.habr.com

Přidat komentář