Stort interview med Cliff Click — faderen til JIT-kompileringen i Java

Stort interview med Cliff Click — faderen til JIT-kompileringen i JavaCliff Click — CTO for Cratus (IoT sensors for process improvement), founder and co-founder of several startups (including Rocket Realtime School, Neurensic, and H2O.ai) with multiple successful exits. Cliff wrote his first compiler at 15 years old (Pascal for TRS Z-80)! He is most known for his work on C2 in Java (the Sea of Nodes IR). This compiler showed the world that JIT could produce quality code, which became one of the factors in establishing Java as one of the main modern software platforms. Later, Cliff helped Azul Systems build an 864-core mainframe with software in pure Java that supported GC pauses on a 500-gigabyte heap within 10 milliseconds. In general, Cliff has worked on all aspects of the JVM.

 
This Hub Post is a large interview with Cliff. We will discuss the following topics:

  • Transition to low-level optimizations
  • How to perform a large refactoring
  • Cost model
  • Learning low-level optimizations
  • Practical examples of performance improvement
  • Why create your own programming language
  • Career of a performance engineer
  • Technical challenges
  • A bit about register allocation and multi-core systems
  • The biggest challenge in life

The interviewers are:

  • Andrey Satarin from Amazon Web Services. In his career, he has worked on a variety of projects: testing distributed NewSQL databases at Yandex, a cloud detection system at Kaspersky Lab, a multiplayer game at Mail.ru, and a currency pricing service at Deutsche Bank. He's interested in testing large-scale backend and distributed systems.
  • Vladimir Sitnikov from Netcracker. He has worked for ten years on the performance and scalability of NetCracker OS — software used by telecom operators for automating network management processes and network equipment. He is passionate about Java and Oracle Database performance. Author of more than a dozen performance improvements in the official PostgreSQL JDBC driver.

Transition to low-level optimizations

Andrey: You are a well-known figure in the world of JIT compilation, Java, and performance work in general, right? 

Cliff: That's right!

Andrey: Let's start with general questions about working on performance. What do you think about the choice between high-level and low-level optimizations like working at the CPU level?

Cliff: Her er det ganske enkelt. Den hurtigste kode er den, der aldrig kĂžres. Derfor skal man altid starte med et hĂžjt niveau og arbejde med algoritmerne. En bedre tidskompleksitet vil slĂ„ en dĂ„rligere, medmindre der er nogle ret store konstanter involveret. Lav-niveau ting kommer sidst. Normalt, hvis du har optimeret hele den Ăžvrige stak godt nok, og der stadig er noget interessant tilbage – sĂ„ er det lav-niveau. Men hvordan starter man med det hĂžje niveau? Hvordan ved man, at man har gjort tilstrĂŠkkeligt arbejde pĂ„ hĂžjt niveau? NĂ„... ikke rigtig. Der er ingen fĂŠrdige opskrifter. Du skal forstĂ„ problemet, beslutte, hvad du vil gĂžre (for ikke at lave unĂždvendige skridt senere), og sĂ„ kan du tage fat pĂ„ profilleren, som kan sige noget nyttigt. PĂ„ et tidspunkt forstĂ„r du selv, at du har fjernet unĂždvendige elementer, og det er tid til at fokusere pĂ„ finjustering af lav niveau. Det er bestemt en sĂŠrlig form for kunst. Mange mennesker laver unĂždvendige ting, men arbejder sĂ„ hurtigt, at de ikke har tid til at bekymre sig om ydeevnen. Men det er, indtil spĂžrgsmĂ„let bliver kritisk. Normalt er 99% af tiden ingen interesseret i, hvad jeg laver, indtil der opstĂ„r noget vigtigt pĂ„ den kritiske vej, som nogen bekymrer sig om. Og sĂ„ begynder alle at stille spĂžrgsmĂ„l som: 'Hvorfor fungerede det ikke perfekt fra starten af?' Generelt er der altid noget at forbedre i ydeevnen. Men 99% af tiden har du ikke noget at gribe fat i! Du prĂžver bare at fĂ„ noget til at fungere, og i lĂžbet af det forstĂ„r du, hvad der er vigtigt. Du kan aldrig vide pĂ„ forhĂ„nd, at denne specifikke del skal gĂžres perfekt, sĂ„ essensen er, at du skal vĂŠre perfekt i alt. Og det er umuligt, og du gĂžr det ikke. Der er altid mange ting, der skal repareres – og det er helt normalt.

How to perform a large refactoring

Andrey: Hvordan arbejder du med ydeevnen? Det er jo et gennemgÄende problem. Har du for eksempel vÊret nÞdt til at arbejde med problemer, der opstÄr pÄ grund af overlapning af en stor mÊngde eksisterende funktionalitet?

Cliff: Jeg prĂžver at undgĂ„ dette. Hvis jeg ved, at ydeevnen vil blive et problem, tĂŠnker jeg over det, fĂžr jeg begynder at kode, isĂŠr nĂ„r det kommer til datastrukturer. Men ofte opdager man det fĂžrst meget senere. Og sĂ„ mĂ„ man tage drastiske skridt og gĂžre det, jeg kalder «genskriv og hersk»: man skal tage fat i en stor del. En del af koden skal stadig skrives om pĂ„ grund af ydeevneproblemer eller andet. Uanset Ă„rsagen til at skrive koden om, er det nĂŠsten altid bedre at skrive en stĂžrre del om end en mindre del. I det Ăžjeblik begynder alle at ryste af frygt: «Äh gud, vi kan ikke rĂžre sĂ„ meget kode!» Men faktisk fungerer en sĂ„dan tilgang nĂŠsten altid meget bedre. Man skal straks tage fat pĂ„ det store problem, skitsere en stor cirkel omkring det og sige: alt inden for cirklen, det vil jeg skrive om. GrĂŠnsen er meget mindre end det indhold, der ligger inden for den, som skal udskiftes. Og hvis en sĂ„dan afgrĂŠnsning gĂžr det muligt at gĂžre arbejdet inden i perfekt – sĂ„ har du frie hĂŠnder, gĂžr hvad du vil. SĂ„ snart du har forstĂ„et problemet, bliver geniskrivningsprocessen meget nemmere, sĂ„ tag en stor bid!
Samtidig, nÄr du genwriter i store bidder og forstÄr, at ydeevnen vil blive et problem, kan du begynde at bekymre dig om det med det samme. Dette bliver ofte til enkle ting som «kopier ikke data, hÄndter data sÄ enkelt som muligt, gÞr dem mindre». I store genskrivninger er der standardmetoder til at forbedre ydeevnen. Og de handler nÊsten altid om data.

Cost model

Andrey: I en af podcasterne talte du om omkostningsmodeller i forbindelse med ydeevne. Kan du forklare, hvad du mente med det?

Cliff: SelvfĂžlgelig. Jeg blev fĂždt i en tid, hvor processorens ydeevne var ekstremt vigtig. Og denne ĂŠra vender tilbage – skĂŠbnen er ikke uden ironi. Jeg begyndte at leve i tiderne med 8-bit maskiner, min fĂžrste computer arbejdede med 256 bytes. Ja, bytes. Alt var meget lille. Man skulle tĂŠlle instruktioner, og sĂ„ snart vi begyndte at bevĂŠge os op ad stakken af programmeringssprog, tog sprogene mere og mere ansvar. Der var assembler, sĂ„ Basic, sĂ„ C, og C tog sig af mange detaljer, som registreringsfordeling og instruktionsevaluering. Men der var alt sammen ret klart, og hvis jeg lavede en peger til en instansvariabel, ville jeg fĂ„ load, og denne instruktion havde en kendt omkostning. Hardwaren leverede et kendt antal maskincykler, sĂ„ hastigheden af forskellige operationer kunne let beregnes ved at lĂŠgge alle instruktioner sammen, som du planlagde at kĂžre. Hver sammenligning/test/forgrening/opkald/load/store kunne samles og man kunne sige: det er tiden for udfĂžrelsen. NĂ„r man forbedrer ydeevnen, vil man helt sikkert bemĂŠrke, hvilke tal der svarer til de smĂ„, varme cykler. 
Men sĂ„ snart du skifter til Java, Python og lignende ting, bevĂŠger du dig meget hurtigt vĂŠk fra det lave hardware-niveau. Hvad er omkostningen ved at kalde en getter i Java? Hvis JIT i HotSpot har gjort det rigtigt, inlinet, sĂ„ bliver det et load, men hvis det ikke gjorde det – bliver det et funktionsopkald. Da opkaldet ligger pĂ„ det varme cyklus, vil det ophĂŠve alle andre optimeringer i denne cyklus. Derfor vil den reelle omkostning vĂŠre meget hĂžjere. Og man mister straks evnen til at se pĂ„ et kodestykke og forstĂ„, hvad det koster at udfĂžre det i forhold til processorens klokkefrekvens, anvendt hukommelse og cache. Alt dette bliver interessant, nĂ„r man virkelig graver ned i ydeevnen.
Vi befinder os nu i en situation, hvor processorernes hastigheder nĂŠsten ikke er steget i et helt Ă„rti. De gamle tider er tilbage! Du kan ikke lĂŠngere regne med god enkelttrĂ„det ydeevne. Men hvis du pludselig skal beskĂŠftige dig med parallel computing – er det sindssygt svĂŠrt, alle ser pĂ„ dig som om du er James Bond. Ti gange acceleration forekommer sĂŠdvanligvis der, hvor nogen har overset noget. Parallellitet krĂŠver meget arbejde. For at opnĂ„ den ti-foldige acceleration skal du forstĂ„ omkostningsmodellen. Hvad koster hvad, og hvor meget? Og for det skal du forstĂ„, hvordan sproget passer ind i det underliggende hardware.
Martin Thompson fandt et fremragende ord til sin blog Mechanical Sympathy! Det er vigtigt at forstÄ, hvad hardwaren forsÞger at gÞre, hvordan den vil gÞre det, og hvorfor den overhovedet gÞr det, den gÞr. Ved at bruge denne forstÄelse er det forholdsvis enkelt at begynde at tÊlle instruktioner og finde ud af, hvor tiden bruges. Hvis du derimod ikke har den rette baggrund, leder du bare efter en sort kat i et mÞrkt rum. Jeg ser konstant folk, der optimerer ydeevnen, uden den mindste idé om, hvad pokker de egentlig laver. De kÊmper meget og kommer ikke rigtig noget sted. Og nÄr jeg tager den samme kode, tilfÞjer et par smÄ tweaks og opnÄr fem- eller ti-foldig acceleration, siger de: NÄ, det er ikke fair, vi vidste jo, at du var bedre. Utroligt. Hvad var det nu, jeg sagde
 omkostningsmodellen handler om, hvad for kode du skriver, og hvor hurtigt den i gennemsnit kÞrer i den overordnede sammenhÊng.

Andrey: Og hvordan holder man sÄ sÄ meget i hovedet? OpnÄs det gennem en masse erfaring, eller? Hvor fÄr man sÄdan erfaring fra?

Cliff: NÄ, jeg har ikke fÄet min erfaring den nemmeste vej. Jeg programmerede i assembler tilbage, da man kunne finde ud af hver enkelt instruktion. Det lyder dumt, men siden da har jeg for evigt haft et sÊt Z80-instruktioner i hukommelsen. Jeg kan ikke huske folks navne et minut efter samtalen, men jeg husker koden skrevet for 40 Är siden. Det er sjovt, det ligner et 'idiot-savante».

Learning low-level optimizations

Andrey: Er der nogen lettere mÄde at komme ind i det pÄ?

Cliff: Ja og nej. Hardwaren, vi alle bruger, har ikke ĂŠndret sig sĂ„ meget i denne tid. Alle bruger x86, undtagen smartphones med Arm. Hvis du ikke arbejder med hardcore embedded udvikling, sĂ„ har du det samme som alle andre. Godt, videre. Instruktionerne har heller ikke ĂŠndret sig i Ă„rtier. Du skal tage hen og skrive noget i Assembly. Lidt, men nok til at begynde at forstĂ„. I ser mĂ„ske grinende ud, men jeg taler helt alvorligt. Det er nĂždvendigt at forstĂ„ forholdet mellem sprog og hardware. Derefter skal du begynde at skrive lidt og lave en lille legetĂžjscompiler til et lille legetĂžjssprog. “LegetĂžj” betyder, at du skal lave det inden for rimelig tid. Det kan vĂŠre super enkelt, men det skal generere instruktioner. Handlingen med at generere instruktioner vil gĂžre det muligt at forstĂ„ omkostningsmodellen for broen mellem den hĂžjniveau kode, som alle skriver, og maskinkoden, der kĂžrer pĂ„ hardwaren. Dette forhold vil brĂŠnde sig ind i hjernen, nĂ„r man skriver compiler. Selv den mest simple compiler. Herefter kan man begynde at kigge pĂ„ Java og se, at dens semantiske klĂžft er meget dybere, og at det er langt mere kompliceret at bygge broer over den. I Java er det meget svĂŠrere at forstĂ„, om vores bro er god eller dĂ„rlig, hvad der vil fĂ„ den til at kollapsere, og hvad der ikke vil. Men du har brug for et udgangspunkt, nĂ„r du kigger pĂ„ koden og forstĂ„r:
Hvor kan man finde en prismodel? Man kan naturligvis lĂŠse noget... Men jeg tror, den bedste mĂ„de er at handle. At lave en lille compiler vil vĂŠre den bedste mĂ„de at forstĂ„ prismodellen pĂ„ og fĂ„ den ind i sin egen bevidsthed. En lille compiler, der kunne bruges til at programmere en mikrobĂžlgeovn – det er en opgave for en nybegynder. Jeg mener, hvis du allerede har programmeringsfĂŠrdigheder, burde det vĂŠre tilstrĂŠkkeligt. Alle disse ting som at parse en streng, der vil vĂŠre et eller andet algebraisk udtryk, trĂŠkke instruktioner til matematiske operationer ud i den rigtige rĂŠkkefĂžlge, tage de rette vĂŠrdier fra registrene – alt dette gĂžres pĂ„ et Ăžjeblik. Og mens du gĂžr det, vil det blive indprentet i din hjerne. Jeg tror, alle ved, hvad en compiler gĂžr. Og det vil give forstĂ„else for prismodellen.

Practical examples of performance improvement

Andrey: Hvad andet bÞr man vÊre opmÊrksom pÄ, nÄr man arbejder med ydeevne?

Cliff: Datastrukturer. For resten, jeg har ikke haft disse lektioner i lang tid... Rocket School. Det var sjovt, men krĂŠvede sĂ„ meget arbejde, og jeg har jo ogsĂ„ et liv! NĂ„. I et af de store og interessante kurser, "Hvor kommer din performance hen?", gav jeg studerende et eksempel: To og en halv gigabyte fintech-data blev lĂŠst fra en CSV-fil og derefter skulle antallet af solgte produkter beregnes. Almindelige tick-markedsdata. UDP-pakker, der blev omdannet til tekstformat siden 70'erne. Chicago Mercantile Exchange – forskellige ting som olie, majs, soja og sĂ„ videre. Man skulle tĂŠlle disse produkter, antallet af handler, gennemsnitligt transaktionsvolumen osv. Det er forholdsvis simpel handelsmatematik: finde produktkoden (det er 1-2 tegn i en hash-tabel), fĂ„ summen, tilfĂžje den til et af handelsbatches, tilfĂžje volumen, tilfĂžje omkostninger, og et par andre ting. Meget simpel matematik. Den legetĂžjsimplementering var meget ligetil: alt ligger i filen, jeg lĂŠser filen og bevĂŠger mig gennem den, opdeler de enkelte poster til Java-strenge, finder de nĂždvendige ting i dem og lĂŠgger dem sammen ifĂžlge ovenstĂ„ende matematik. Og det fungerer med en vis hastighed.

Med en sĂ„dan tilgang er det Ă„benlyst, hvad der foregĂ„r, og parallelle beregninger vil ikke hjĂŠlpe her, korrekt? Det viser sig, at man kun ved at vĂŠlge de rigtige datatyper kan opnĂ„ en femfoldig stigning i ydeevnen. Og det overrasker selv erfarne programmĂžrer! I mit specifikke tilfĂŠlde handlede fokus om, at man ikke bĂžr lave hukommelsesallokeringer i en varm cyklus. NĂ„, det er ikke hele sandheden, men generelt set skal man ikke allokere "hver gang i X", nĂ„r X er stort nok. NĂ„r X er to og en halv gigabyte, bĂžr man ikke allokere noget "hver gang for en bogstav", eller "hver gang for en linje", eller "hver gang for et felt", ingenting af den slags. Det er netop her, tiden gĂ„r tabt. Hvordan fungerer det overhovedet? Forestil dig, at jeg laver et kald String.split() eller BufferedReader.readLine(). Readline der laver en streng fra en rĂŠkke bytes, der er sendt over netvĂŠrket, Ă©n gang for hver linje, for hver af de hundrede millioner linjer. Jeg tager denne linje, analyserer den og smider den vĂŠk. Hvorfor smider jeg den vĂŠk – nĂ„, jeg har jo allerede behandlet den, det er det. SĂ„ for hver byte, der er lĂŠst fra disse 2.7G, vil der blive skrevet to tegn i strengen, altsĂ„ allerede 5.4G, og de er ikke lĂŠngere nyttige for mig, sĂ„ jeg smider dem vĂŠk. Hvis man ser pĂ„ hukommelsens bĂ„ndbredde, sĂ„ indlĂŠser vi 2.7G, som gĂ„r gennem hukommelsen og hukommelsesbussen i processor, og derefter sendes der to gange mere til strengen, der ligger i hukommelsen, og alt dette bearbejdes, nĂ„r hver ny streng oprettes. Men jeg skal lĂŠse den, hardwaren lĂŠser den, selvom alt senere bliver bearbejdet. Og jeg skal skrive den, fordi jeg har oprettet en streng, og caches er fyldt – cache kan ikke rumme 2.7G. SĂ„ for hver lĂŠst byte lĂŠser jeg ogsĂ„ to ekstra bytes og skriver to ekstra bytes, og til sidst har de et forhold pĂ„ 4:1 – vi spilder pĂ„ den mĂ„de hukommelsens bĂ„ndbredde. Og det viser sig, at hvis jeg gĂžr String.split() – sĂ„ gĂžr jeg det langt fra sidste gang, derinde kan der vĂŠre yderligere 6-7 felter. Derfor fĂžrer den klassiske kode til lĂŠsning af CSV med efterfĂžlgende parsing af strenge til tab af hukommelsesbĂ„ndbredde pĂ„ omkring 14:1 i forhold til, hvad man faktisk gerne vil have. Hvis man undgĂ„r disse allokeringer, kan man opnĂ„ en femfoldig acceleration.

Og det er ikke, fordi det er sÊrligt svÊrt. Hvis du ser pÄ koden fra den rette vinkel, sÄ bliver alt dette ret simpelt, sÄ snart du indser essensen af problemet. Du skal overhovedet ikke stoppe med at allokere hukommelse: problemet er kun, at du allokerer noget, og det dÞr straks, hvilket forbruger en vigtig ressource, som i dette tilfÊlde er hukommelsesbÄndbredde. Og alt dette resulterer i et fald i ydeevnen. PÄ x86 skal man normalt aktivt bruge CPU-taktter, men her har du allerede forbrugt al hukommelse langt tidligere. LÞsningen er at reducere antallet af allokeringer. 
En anden del af problemet er, at hvis du kĂžrer en profiler, nĂ„r hukommelsesbĂ„ndbredden er opbrugt, prĂŠcis i det Ăžjeblik, hvor det sker, forventer du ofte at fĂ„ cache tilbage, fordi den er fyldt med skrald, som du lige har skabt, med alle disse rĂŠkker. SĂ„ hver load- eller store-operation bliver langsom, fordi de fĂžrer til cache-misser – hele cachen er blevet langsom, mens den venter pĂ„, at skraldet forlader den. Derfor viser profiler kun varmt tilfĂŠldigt stĂžj, spredt langs hele cyklussen – der vil ikke vĂŠre nogen separat varm instruktion eller et sted i koden. Kun stĂžj. Og hvis du kigger pĂ„ GC-cyklusserne, vil alle vĂŠre i Young Generation og superhurtige – mikrosekunder eller millisekunder maksimalt. Al denne hukommelse dĂžr Ăžjeblikkeligt. Du allokerer milliarder af gigabyte, og den klipper dem af, og klipper dem af, og klipper dem af. Alt dette sker meget hurtigt. SĂ„ der er billige GC-cyklusser, varm stĂžj langs hele cyklussen, men vi Ăžnsker at opnĂ„ en 5-dobbelt acceleration. PĂ„ det tidspunkt skal noget gĂ„ op for en: «hvorfor?!». Overbelastning af hukommelsesbĂ„ndbredden vises ikke i den klassiske debugger; du skal kĂžre en debugger for hardware-performance-tĂŠllere og se det selv direkte. Og ikke direkte kan du mistĂŠnke det ud fra disse tre symptomer. Det tredje symptom er, nĂ„r du ser, hvad du allokerer, spĂžrger profiler, og den svarer: «Du har lavet en milliard rĂŠkker, men GC arbejdede gratis». SĂ„ snart dette sker, indser du, at du har skabt for mange objekter og har forbrugt hele hukommelsesbĂ„ndbredden. Der er en mĂ„de at finde ud af dette pĂ„, men den er ikke indlysende. 

Problemet ligger i datakonstru ktionen: den rĂ„ struktur, der ligger bag alt dette, er for stor; den fylder 2.7G pĂ„ disken, sĂ„ det er ikke Ăžnskeligt at lave en kopi af denne ting – man vil gerne indlĂŠse den direkte fra netvĂŠrksbytebufferen til registre, sĂ„ man ikke lĂŠser og skriver frem og tilbage fem gange. DesvĂŠrre giver Java som standard ikke sĂ„dan et bibliotek i JDK. Men det er jo trivielt, ikke? I bund og grund er det 5-10 linjer kode, der vil implementere en egen bufferloader til linjer, der efterligner opfĂžrselen af string-klassen, samtidig med at den fungerer som en wrapper omkring den underliggende bytebuffer. Resultatet bliver, at du nĂŠsten arbejder som med strenge, men i virkeligheden bevĂŠger der sig blot pointere til bufferen, og rĂ„ bytes kopieres ikke nogen steder, og pĂ„ den mĂ„de genbruges de samme buffere igen og igen, og operativsystemet er glad for at tage sig af de opgaver, det er beregnet til, sĂ„som skjult dobbeltbuffering af disse bytebuffere, sĂ„ du ikke lĂŠngere maler en endelĂžs strĂžm af unĂždvendige data. Forresten, forstĂ„r I, at der med GC garanteres, at hver allokering af hukommelse ikke vil vĂŠre synlig for processoren efter den sidste GC-cyklus? Derfor kan alt dette slet ikke vĂŠre i cachen, og sĂ„ sker der 100% garanti for et cache-miss. Ved arbejde med en pointer, tager det pĂ„ x86 1-2 clock cycles at lĂŠse et register fra hukommelsen, og sĂ„ snart det sker, betaler du, betaler du, betaler du, fordi al hukommelse er pĂ„ NINE caches – og det er prisen for hukommelsesallokering. Den reelle pris.

Med andre ord er datastrukturer det, der er svĂŠrest at ĂŠndre. Og sĂ„ snart du indser, at du har valgt en forkert datastruktur, der i fremtiden vil drĂŠbe prĂŠstationen, krĂŠver det normalt betydelig arbejde at ĂŠndre det, men hvis du ikke gĂžr det, vil situationen kun blive vĂŠrre. FĂžrst og fremmest skal man tĂŠnke pĂ„ datastrukturer; det er vigtigt. Den primĂŠre omkostning ligger her pĂ„ tunge datastrukturer, som folk begynder at bruge med tanken: "Jeg kopierede datastruktur X til datastruktur Y, fordi Y ser bedre ud for mig." Men kopieringsoperationen (som virker billig) bruger faktisk bĂ„ndbredde, og her ligger alt det mistede udfĂžrelsestid. Hvis jeg har en gigantisk streng med JSON, og jeg vil omdanne den til et struktureret DOM-trĂŠ af POJO'er eller noget lignende, vil parsing af denne streng og opbygningen af POJO'er, og derefter et nyt opkald til POJO'erne senere, medfĂžre unĂždvendige omkostninger – det er ikke billigt. Medmindre du planlĂŠgger at behandle POJO'erne meget oftere end strengen. Som en hurtig lĂžsning kan du prĂžve at dekode strengen og trĂŠkkes nĂždvendige informationer ud uden at omdanne til POJO'er. Hvis alt dette foregĂ„r pĂ„ en vej, hvor maksimal ydeevne krĂŠves, er der ingen POJO'er – du skal finde en mĂ„de at arbejde direkte med strengen pĂ„.

Why create your own programming language

Andrey: Du sagde, at for at forstÄ omkostningsmodellen, skal man skrive sit eget lille sprog ...

Cliff: Ikke et sprog, men en compiler. Sprog og compiler er to forskellige ting. Den vigtigste forskel er i dit hoved. 

Andrey: For Ăžvrigt, som jeg ved, eksperimenterer du med at skabe dine egne sprog. Hvorfor?

Cliff: Fordi jeg kan! Jeg er halvt pensioneret, sÄ det her er mit hobby. Jeg har hele mit liv implementeret andres sprog. Og sÄ har jeg arbejdet meget med kodestil. OgsÄ fordi jeg ser problemer i andre sprog. Jeg kan se, at der er bedre mÄder at gÞre velkendte ting pÄ. Og jeg ville bruge dem. Jeg er bare trÊt af at se problemer i mig selv, i Java, i Python, i hvilket som helst andet sprog. Jeg skriver nu i React Native, JavaScript og Elm som en hobby, der ikke handler om pension, men om aktivt arbejde. Og jeg skriver ogsÄ i Python, og sandsynligvis vil jeg fortsÊtte med at arbejde med maskinlÊring for Java-backends. Der er mange populÊre sprog, og hvert af dem har interessante egenskaber. Hvert sprog er godt til noget, og man kan prÞve at samle alle disse funktioner. SÄ jeg studerer de ting, der interesserer mig, adfÊrd af sprog, og prÞver at finde pÄ fornuftig semantik. Og indtil videre klarer jeg mig godt! I Þjeblikket kÊmper jeg med semantik for hukommelsen, fordi jeg gerne vil have det, som i C og Java, og fÄ en stÊrk hukommelsesmodel og hukommelsessemantik for load og store. Samtidig vil jeg have automatisk typeaflednings som i Haskell. Jeg prÞver at blande Haskell-lignende typeaflednings med hukommelse, der fungerer som i C og Java. Det har jeg arbejdet med de sidste 2-3 mÄneder, for eksempel.

Andrey: Hvis du bygger et sprog, der tager de bedste aspekter fra andre sprog, har du tÊnkt over, at nogen mÄske vil gÞre det omvendte: tage dine ideer og bruge dem i deres eget?

Cliff: SÄdan opstÄr der nye sprog! Hvorfor ligner Java C? Fordi C havde en god syntaks, som alle forstod, og Java blev inspireret af den syntaks, tilfÞjede type-sikkerhed, arrays grÊnsekontrol, GC, og de forbedrede nogle ting fra C. De tilfÞjede deres egne. Men de var ret meget inspireret, ikke? Alle stÄr pÄ skuldrene af kÊmperne, der var fÞr dig - sÄdan gÞr man fremskridt.

Andrey: Som jeg forstÄr det, vil dit sprog vÊre sikkert i forhold til brug af hukommelse. Har du overvejet at implementere noget som borrow checker fra Rust? Har du kigget pÄ det, hvad synes du?

Cliff: Jeg har allerede skrevet i C i en evighed, med alt dette malloc og free, og jeg administrerer livscyklussen manuelt. Ved du, 90-95% af den manuelt styrede livscyklus har den samme struktur. Og det er meget, meget smertefuldt at hĂ„ndtere dette manuelt. Jeg ville Ăžnske, at compilerens output bare sagde, hvad der sker, og hvad jeg har opnĂ„et med mine handlinger. For nogle ting gĂžr borrow checker dette ud af boksen. Og det skal ogsĂ„ automatisk udlede information, forstĂ„ alt og endda ikke overbelaste mig med at skulle formulere den forstĂ„else. Det skal lave mindst en lokal escape-analyse, og kun hvis det ikke lykkes, sĂ„ skal der tilfĂžjes typeannoteringer, der beskriver livscyklussen – og en sĂ„dan ordning er langt mere kompleks end borrow checker eller overhovedet enhver eksisterende hukommelseschecker. Valget mellem 'alt er i orden' og 'jeg forstod ikke noget' — nej, der skal vĂŠre noget bedre. 
Som en person, der har skrevet meget kode i C, mener jeg, at stĂžtte til automatisk livscyklusstyring er en af de vigtigste ting. Jeg er ogsĂ„ trĂŠt af, hvor meget Java bruger hukommelse, og en af de stĂžrste klager er omkring GC. NĂ„r du tildeler hukommelse i Java, fĂ„r du ikke den hukommelse tilbage, der var lokal i den sidste GC-cyklus. I sprog med mere prĂŠcis hukommelseskontrol er det ikke sĂ„dan. Hvis du kalder malloc, fĂ„r du straks hukommelse, der netop er blevet brugt. Normalt laver du nogle midlertidige ting med hukommelsen og returnerer den straks. Og den gĂ„r straks tilbage til malloc-poolen, og den nĂŠste malloc-cyklus trĂŠkker den ud igen. Derfor reduceres det faktiske hukommelsesforbrug til mĂŠngden af levende objekter pĂ„ et givet tidspunkt plus lĂŠkager. Og hvis du ikke lĂŠkker pĂ„ en helt skandalĂžs mĂ„de, vil det meste af hukommelsen lande i cache og processoren, og det fungerer hurtigt. Men det krĂŠver meget manuel hukommelseshĂ„ndtering ved hjĂŠlp af malloc og free, der kaldes i den rigtige rĂŠkkefĂžlge og pĂ„ det rigtige sted. Rust kan selv hĂ„ndtere dette korrekt og i mange tilfĂŠlde endda give bedre ydeevne, da hukommelsesforbruget begrĂŠnses til de aktuelle beregninger – i modsĂŠtning til at vente pĂ„ den nĂŠste GC-cyklus, der frigiver hukommelse. Resultatet er, at vi har fĂ„et en meget interessant mĂ„de at forbedre ydeevnen pĂ„. Og ret kraftfuld – jeg har arbejdet med sĂ„danne ting i databehandling for fintech, og det kunne give en acceleration pĂ„ omkring fem gange. Det er en ret stor acceleration, isĂŠr i en verden, hvor processorer ikke bliver hurtigere, men vi stadig venter pĂ„ forbedringer.

Career of a performance engineer

Andrey: Jeg vil ogsĂ„ gerne spĂžrge om din karriere generelt. Du blev berĂžmt for dit arbejde med JIT i HotSpot og bevĂŠgede dig derefter til Azul – og det er ogsĂ„ et JVM-selskab. Men du har arbejdet mere med hardware end software. Og sĂ„ pludselig skiftede du til Big Data og Machine Learning, og senere til svindelbekĂŠmpelse. Hvordan gik det til? Det er meget forskellige udviklingsomrĂ„der.

Cliff: Jeg har arbejdet med programmering i lang tid og har vĂŠret involveret i mange forskellige projekter. Og nĂ„r folk siger: «Åh, du er ham, der lavede JIT til Java!», er det altid sjovt. FĂžr det arbejdede jeg med en klon af PostScript – det sprog, som Apple engang brugte til deres laserprintere. Og fĂžr det implementerede jeg Forth-sproget. Jeg tror, at min gennemgĂ„ende interesse er udvikling af vĂŠrktĂžjer. Jeg har hele mit liv lavet vĂŠrktĂžjer, som hjĂŠlper andre med at skrive deres fantastiske programmer. Men jeg har ogsĂ„ arbejdet med udvikling af operativsystemer, drivere, kernel-niveau debuggere og sprog til operativsystemudvikling, der startede simpelt, men som blev mere og mere komplekse over tid. Men det primĂŠre fokus er stadig udvikling af vĂŠrktĂžjer. En stor del af mit liv er blevet tilbragt mellem Azul og Sun, og det handlede om Java. Men da jeg begyndte med Big Data og Machine Learning, tog jeg igen min festhat pĂ„ og sagde: «Åh, nu stĂ„r vi over for et ikke-trivielt problem, og der sker virkelig en masse interessante ting og mennesker, der laver noget.» Det er en fantastisk vej for udvikling, som er vĂŠrd at gĂ„.

Ja, jeg elsker virkelig distribueret computing. Mit fĂžrste job var i studietiden med C, pĂ„ et reklameprojekt. Det handlede om distribueret computing pĂ„ Zilog Z80-chip, som indsamlede data til analog optisk tekstgenkendelse, der blev udfĂžrt af en ĂŠgte analog analyser. Det var et fedt og helt unormalt emne. Men der var problemer; en del blev ikke genkendt korrekt, sĂ„ man skulle tage billedet frem og vise det til en person, der allerede havde lĂŠst det med Ăžjnene og kunne fortĂŠlle, hvad det handlede om. Derfor var der job med data, og disse job havde deres eget sprog. Der var en backend, der behandlede det hele – fungerende Z80'er kĂžrte parallelt med vt100-terminaler – Ă©n pr. person, og der var en model for parallel programmering pĂ„ Z80. En slags fĂŠlles hukommelse, som alle Z80 delte inden for en stjernelignende konfiguration; bĂŠkplen blev delt, og halvdelen af RAM'en blev delt inden for netvĂŠrket, og den anden halvdel var privat eller gik til noget andet. En meningsfuld kompleks parallel distribueret system med delt... halv-delt hukommelse. HvornĂ„r var det her... Kan nĂŠsten ikke huske det, et sted i midten af 80'erne. Ret lang tid siden. 
Ja, lad os sige, at 30 Ă„r er ret lang tid. Opgaver relateret til distribueret computing har eksisteret lĂŠnge, og folk har kĂŠmpet med det i lang tid. Beowulf-klystrer. SĂ„danne klystrer ser ud som
 For eksempel: der er Ethernet, og din hurtige x86 er tilsluttet dette Ethernet, og nu Ăžnsker du at fĂ„ fat i fake shared memory, fordi ingen kunne dengang arbejde med kodning af distribuerede beregninger, det var for svĂŠrt, og derfor var der fake shared memory med beskyttelse af hukommelsessider pĂ„ x86. Hvis du skrev til denne side, fortalte vi de andre processorer, at hvis de fik adgang til den samme shared memory, skulle den hentes fra dig, og pĂ„ den mĂ„de opstod der noget som en protokol til stĂžtte for cache-koherens og software til dette. En interessant koncept. Det virkelige problem var selvfĂžlgelig et andet. Alt dette fungerede, men du fik hurtigt problemer med ydeevnen, for ingen forstod ydeevnemodellen pĂ„ et tilstrĂŠkkeligt godt niveau – hvilke adgangsmĂžnstre til hukommelsen der var, hvordan man fik noderne til ikke konstant at pinge hinanden, og sĂ„ videre.

I H2O har jeg fundet ud af fĂžlgende: selv udviklerne er ansvarlige for at bestemme, hvor parallelismen gemmer sig, og hvor den ikke gĂžr. Jeg har skabt en kodningsmodel, der gĂžr det let og enkelt at skrive hĂžjtydende kode. Men at skrive langsomt fungerende kode er svĂŠrt, og det vil se dĂ„rligt ud. Man skal virkelig gĂžre en indsats for at skrive langsom kode; det krĂŠver ikke-standardmetoder. Bremsende kode er synlig ved fĂžrste Ăžjekast. Som fĂžlge heraf skrives der normalt kode, der fungerer hurtigt, men man mĂ„ finde ud af, hvad man skal gĂžre i tilfĂŠlde af delt hukommelse. Alt dette er knyttet til store arrays, og opfĂžrelsen der minder om ikke-flygtige store arrays i parallelt Java. TĂŠnk pĂ„ det pĂ„ denne mĂ„de: to trĂ„de skriver til et parallelt array, en af dem vinder, og den anden, selvfĂžlgelig, taber, og du ved ikke, hvem der er hvem. Hvis de ikke er flygtige, kan rĂŠkkefĂžlgen vĂŠre hvad som helst – og det fungerer faktisk rigtig godt. Folk bekymrer sig virkelig om rĂŠkkefĂžlgen af operationer, de placerer volatile korrekt og forventer pĂ„ de rigtige steder problemer med ydeevne relateret til hukommelse. Ellers ville de bare skrive kode som lĂžkker fra 1 til N, hvor N er nogle trillioner, i hĂ„bet om at alle komplekse tilfĂŠlde automatisk bliver parallelle – og det virker ikke der. Men i H2O er det hverken Java eller Scala, man kan betragte det som 'Java minus minus', hvis man vil. Det er en meget forstĂ„elig programmeringsstil, og den ligner at skrive simpel kode i C eller Java med lĂžkker og arrays. Men samtidig kan man hĂ„ndtere terabyte af hukommelse. Jeg bruger stadig H2O. Af og til bruger jeg det i forskellige projekter – og det er stadig den hurtigste ting, der overgĂ„r konkurrenterne med flere hundrede gange. Hvis du arbejder med Big Data med kolonnebaserede data, er det meget svĂŠrt at overgĂ„ H2O.

Technical challenges

Andrey: Hvad har vĂŠret den stĂžrste udfordring i din karriere?

Cliff: Diskuterer vi den tekniske eller ikke-tekniske del af spÞrgsmÄlet? Jeg vil sige, at de stÞrste udfordringer ikke er tekniske. 
NÄr det kommer til tekniske udfordringer, har jeg bare overvundet dem. Jeg ved endda ikke, hvilken der var den stÞrste, men der var flere ret interessante, som tog ret lang tid og mental kamp. Da jeg gik til Sun, var jeg overbevist om, at jeg ville lave en hurtig compiler, mens mange seniorer sagde, at jeg aldrig ville lykkes. Men jeg tog den vej, skrev en compiler helt ned til registerallokatoren, og den var ret hurtig. Den var lige sÄ hurtig som den moderne C1, men pÄ det tidspunkt var allokatoren meget langsommere, og nÄr jeg ser tilbage, var det et problem med den store datastruktur. Jeg havde brug for den for at skrive en grafisk registerallokator, og jeg forstod ikke dilemmaet mellem kodeudtrykkelse og hastighed, som eksisterede i den tid og var meget vigtig. Det viste sig, at datastrukturen normalt overskred cache-stÞrrelsen pÄ dengang x86-arkitekturen, og derfor, hvis jeg oprindeligt antog, at registerallokatoren ville bruge 5-10 procent af tiden pÄ JIT, viste det sig i virkeligheden at vÊre 50 procent.

Tiden gik, og compileren blev stadig mere prĂŠcis og effektiv, den holdt op med at generere frygteligt kode i flere tilfĂŠlde, og ydeevnen begyndte mere og mere at ligne det, som C compileren leverede. Hvis du selvfĂžlgelig ikke skriver noget skrammel, som selv C ikke kan optimere. Hvis du skriver kode som i C, fĂ„r du ogsĂ„ ydeevne som i C i flere tilfĂŠlde. Og jo lĂŠngere hen, desto oftere blev der produceret kode, der asymptotisk matchede C-niveau, registerallokatoren begyndte at ligne noget, der var fĂŠrdigt... uanset om din kode kĂžrte hurtigt eller langsomt. Jeg fortsatte med at arbejde pĂ„ allokatoren for at gĂžre den bedre til allokeringer. Den blev langsommere, men leverede stadig bedre ydeevne i de tilfĂŠlde, hvor ingen kunne klare det. Jeg kunne dykke ind i registerallokatoren, begrave en mĂ„neds arbejde der, og pludselig begyndte al koden at kĂžre 5% hurtigere. Det skete gang pĂ„ gang, og registerallokatoren blev til en slags kunstvĂŠrk – alle elskede eller hadede den, og akademikere stillede spĂžrgsmĂ„l som "hvorfor er alt gjort pĂ„ denne mĂ„de", hvorfor ikke. lineĂŠr scanning, og hvad forskellen er. Svaret er det samme: allocator baseret pĂ„ graffarvning plus meget prĂŠcist arbejde med bufferkode er lig med et vinderredskab, den bedste kombination, som ingen kan overgĂ„. Og det er en ret ikke-Ă„benlys ting. Alt andet, som kompilatoren gĂžr der, er ret velkendte ting, selvom de ogsĂ„ er blevet forfinet til kun kunstens niveau. Jeg har altid lavet ting, der skulle gĂžre kompilatoren til et kunstvĂŠrk. Men intet af dette var noget ekstraordinĂŠrt – bortset fra registerallokatoren. Pointen er, at man nĂžje skal afskĂŠre under belastning, og hvis det sker (jeg kan forklare nĂŠrmere, hvis det er interessant), betyder det, at man kan inlinje mere aggressivt uden risiko for at overskride performance-grafens brudpunkt. I de dage var der mange fuldskala kompilatorer, fyldt med funktioner og gadgets, der havde registerallokatorer, men ingen kunne gĂžre det igen.

Problemet er, at hvis du tilfĂžjer metoder, der kan indlĂŠgges inline, og udvider og udvider omrĂ„det for indligning, sĂ„ overgĂ„r det sĂŠt af vĂŠrdier, der bruges, straks antallet af registre, og man bliver nĂždt til at spilde. Det kritiske niveau opstĂ„r typisk, nĂ„r allokatoren giver op, og en god kandidat til spild stĂ„r over for en anden; man spilder nogle virkelig mĂŠrkelige ting. VĂŠrdien af indligning her ligger i, at du mister en del overhead, overhead pĂ„ kald og lagring; du kan se vĂŠrdierne indeni og kan optimere dem yderligere. Omkostningen ved indligning er, at der dannes et stort antal levende vĂŠrdier, og hvis din registre-allokator spilder mere, end nĂždvendigt, taber du straks. Derfor har de fleste allokatorer et problem: nĂ„r indligningen overskrider en bestemt grĂŠnse, bliver alt spildt, og ydeevnen kan skyde i sĂŠnk. Dem, der implementerer en compiler, tilfĂžjer nogle heuristikker: for eksempel at stoppe indligningen, nĂ„r en vis stĂžrrelse er nĂ„et, da allokationerne vil ĂždelĂŠgge alt. Det fĂžrer til et brud i ydeevnekurven – du indlĂŠser, indlĂŠser, ydeevnen stiger langsomt – og sĂ„ bam! – den falder ned som en hurtig domkraft, fordi du har indlĂŠst for meget. SĂ„dan har det fungeret indtil Java kom. Java krĂŠver meget mere indligning, sĂ„ jeg mĂ„tte gĂžre min allokator meget mere aggressiv, sĂ„ det holder sig oppe i stedet for at falde. Og hvis du har indlĂŠst for meget, begynder den at spilde, men sĂ„ kommer der stadig et punkt, hvor der ikke er mere spild. Det er en interessant observation, som kom til mig ud af ingenting; det er ikke indlysende, men det har givet godt udbytte. Jeg tog fat pĂ„ aggressiv indligning, og det fĂžrte mig til sĂ„danne steder, hvor ydeevnen for Java og C gĂ„r hĂ„nd i hĂ„nd. De er virkelig tĂŠtte – jeg kan skrive kode i Java, der vil vĂŠre betydeligt hurtigere end C-kode og sĂ„ videre, men i gennemsnit, i det store billede, er de nogenlunde sammenlignelige. Jeg tror, at en del af denne fortjeneste ligger i registre-allokatoren, som tillader mig at indlĂŠse sĂ„ dumt som muligt. Jeg indlĂŠser bare alt, hvad jeg ser. SpĂžrgsmĂ„let er, om allokatoren fungerer godt, og om det resulterende kode er fornuftigt. Dette var en stor udfordring: at forstĂ„ alt dette og fĂ„ det til at fungere.

A bit about register allocation and multi-core systems

Vladimir: Problemer som registrering allocation synes at vÊre et evigt emne. Det er interessant, om der nogensinde har vÊret en idé, der sÄ lovende ud, men som sÄ fejlede i praksis?

Cliff: SelvfÞlgelig! Registrering allocation er et omrÄde, hvor du prÞver at finde nogle heuristikker for at lÞse et NP-kompleks problem. Og du vil aldrig kunne opnÄ en perfekt lÞsning, ikke sandt? Det er simpelthen umuligt. Se, Ahead of Time-kompilering - det fungerer ogsÄ dÄrligt. Her handler diskussionen om nogle gennemsnitlige tilfÊlde. Om typisk ydeevne, sÄ du kan tage ud og mÄle noget, du anser for at vÊre god typisk ydeevne - i sidste ende arbejder du jo pÄ at forbedre den! Registrering allocation er et emne, der helt er dedikeret til ydeevne. SÄ snart du har den fÞrste prototype, der fungerer og farver det, der er nÞdvendigt, begynder arbejdet med ydeevnen. Du skal lÊre at mÄle godt. Hvorfor er det vigtigt? Hvis der er klare data, kan du kigge pÄ forskellige omrÄder og se: ah, det hjalp her, men der er det hele gÄet galt! Der opstÄr nogle gode idéer, du tilfÞjer en ny heuristik, og pludselig begynder alt at fungere lidt bedre i gennemsnit. Eller det gÞr det ikke. Jeg har haft mange tilfÊlde, hvor vi kÊmpede for fem procent ydeevne, der adskilte vores udvikling fra den tidligere allocator. Og hver gang ser det sÄdan ud: et sted vandt, et sted tabte. Hvis du har gode vÊrktÞjer til at analysere ydeevne, kan du finde de tabte idéer og forstÄ, hvorfor de taber. MÄske er det bedst at lade det vÊre som det er, eller mÄske er det tid til en mere seriÞs tilgang til finjustering, eller at gÄ og fixe noget andet. Det er en hel rÊkke ting! Jeg lavede denne seje hack, men jeg har brug for ogsÄ den, og den, og den - og deres samlede kombination giver nogle forbedringer. Ensomme kan fejle. SÄdan er naturen ved at arbejde med ydeevnen af NP-komplekse problemer.

Vladimir: Det fÞles som om, at ting som farvning i allocators er en allerede lÞst opgave. NÄ, for dig ser det ud til at vÊre lÞst, hvis man ser pÄ hvad du fortÊller, sÄ er det sÄ vÊrd at...?

Cliff: Det er ikke lĂžst som sĂ„dan. Det er dig, der skal gĂžre det til en "lĂžst" problem. Der er svĂŠre opgaver, og de skal lĂžses. NĂ„r det er gjort, er det tid til at arbejde pĂ„ ydeevne. Dette arbejde skal tages seriĂžst – lave benchmarks, samle metrikker, forklare situationer, hvor dit gamle hack begyndte at fungere igen (eller omvendt, stoppede med at fungere), nĂ„r du ruller tilbage til en tidligere version. Og ikke give op, fĂžr du opnĂ„r noget. Som jeg allerede har sagt, hvis der er fede ideer, der ikke fungerede, men inden for registrering allocation er ideerne ret uendelige. Du kan for eksempel lĂŠse videnskabelige publikationer. Selvom dette omrĂ„de i Ăžjeblikket bevĂŠger sig langsommere og er blevet mere klart end i sin ungdom, arbejder der stadig en hel uendelighed af mennesker pĂ„ dette omrĂ„de, og alle deres ideer er vĂŠrd at prĂžve; de venter bare pĂ„ deres tid. Og du kan ikke sige, hvor gode de er, medmindre du prĂžver dem. Hvor godt de integreres med alt andet i din allocator, eftersom allocatoren laver mange ting, og nogle ideer i din specifikke allocator vil ikke fungere, mens de i en anden allocator gĂžr det uden problemer. Den primĂŠre mĂ„de at vinde for en allocator er at trĂŠkke langsomme ting uden for den primĂŠre bane og tvinge dem til at splitte langs grĂŠnserne for de langsomme veje. SĂ„ hvis du Ăžnsker at starte GC, tage den langsomme rute, deoptimere, kaste undtagelser, alt i den stil – du ved, at disse ting er relativt sjĂŠldne. Og de er virkelig sjĂŠldne, jeg har tjekket. Du laver ekstra arbejde, og takket vĂŠre dette forsvinder mange begrĂŠnsninger pĂ„ disse langsomme veje, men det er ikke sĂ„ vigtigt, fordi de er langsomme, og der fĂŠrdes sjĂŠldent folk der. For eksempel, en nulpeger – det sker aldrig, vel? Du skal have flere veje til forskellige ting, men de mĂ„ ikke blandes pĂ„ den primĂŠre rute. 

Vladimir: Hvad synes du om multicore, nÄr der er tusind kerner? Er det en nyttig ting?

Cliff: Succesen med GPU'en viser, at det er ret nyttigt!

Vladimir: De er ret specialiserede. Og hvad med procesorer til almindeligt brug?

Cliff: NÄ, det var forretningsmodellen for Azul. Svaret kom i en tid, hvor folk virkelig satte pris pÄ forudsigelig ydeevne. Dengang var det svÊrt at skrive parallelt kode. H2O-kodningsmodellen skalerer godt, men den er ikke en generel model. Den er kun lidt mere generel end ved brug af GPU. Taler vi om kompleksiteten ved at udvikle sÄdan noget eller kompleksiteten ved at bruge det? For eksempel, en interessant lektie, som Azul lÊrte mig, noget ret uventet: smÄ caches er helt okay. 

The biggest challenge in life

Vladimir: Hvad med de ikke-tekniske udfordringer?

Cliff: Den stĂžrste udfordring var at undgĂ„ at vĂŠre... venlig og god mod folk. Som fĂžlge heraf befandt jeg mig konstant i ekstremt konfliktfyldte situationer. Situationen, hvor jeg vidste, at alt gik galt, men ikke vidste, hvordan jeg skulle komme videre med at lĂžse disse problemer, og jeg kunne ikke hĂ„ndtere dem. Mange langvarige problemer, der har varet i Ă„rtier, opstod pĂ„ netop den mĂ„de. Det faktum, at der i Java findes kompilatorer C1 og C2, er en direkte fĂžlge af dette. At der i Java i mange Ă„r ikke var flerniveau kompilering, er ogsĂ„ en direkte fĂžlge. Det er Ă„benlyst, at vi havde brug for et sĂ„dant system, men det er ikke Ă„benlyst, hvorfor det ikke eksisterede. Jeg havde problemer med en ingeniĂžr
 eller en gruppe af ingeniĂžrer. For mange Ă„r siden, da jeg begyndte at arbejde i Sun, var jeg
 NĂ„, ikke kun dengang, jeg har generelt altid min egen mening om alting. Og jeg ansĂ„ det for sandhed, at man bare kunne tage sin egen sandhed og fortĂŠlle den direkte. IsĂŠr da jeg var chokerende rigtig det meste af tiden. Og hvis du ikke kan lide denne tilgang
 isĂŠr hvis du Ă„benlyst tager fejl og laver noget sjusk
 Generelt kunne svĂŠrt fĂ„ mennesker tolerere en sĂ„dan kommunikationsform. Selvom nogle kunne, for eksempel jeg. Jeg har bygget hele mit liv pĂ„ meritokratiske principper. Hvis du viser mig noget, der er forkert, vil jeg straks sige: du har sagt noget forkert. Samtidig undskylder jeg selvfĂžlgelig, og alt det der, anerkender fortjenester, hvis der er nogen, og gĂžr andre rigtige handlinger. PĂ„ den anden side har jeg chokerende ret i chokerende stor procentdel af den tid, jeg interagerer med folk. Og det fungerer ikke sĂŠrlig godt i relationer. Jeg prĂžver ikke at vĂŠre venlig, men stiller problemet direkte. “Det her vil aldrig fungere, fordi 1, 2 og 3”. Og de er sĂ„dan: “Åh!” Der var ogsĂ„ andre konsekvenser, som det nok er bedst at springe over: for eksempel der fĂžrte til skilsmisse fra min kone og ti Ă„r med depression efterfĂžlgende.

En udfordring er at kĂŠmpe mod folk og deres opfattelse af, hvad du kan eller ikke kan gĂžre, hvad der er vigtigt, og hvad der ikke er. Der har vĂŠret mange udfordringer omkring kodningsstil. Jeg skriver stadig meget kode, og dengang mĂ„tte jeg endda bremse mig selv, fordi jeg lavede for mange parallelle opgaver og gjorde dem dĂ„rligt, i stedet for at fokusere pĂ„ Ă©n ting. NĂ„r jeg ser tilbage, har jeg skrevet halvdelen af koden til Java JIT-teamet, C2-teamet. Den nĂŠste hurtigste koders skrev halvt sĂ„ hurtigt, den nĂŠste yderligere halvt sĂ„ hurtigt, og det var en eksponentiel nedgang. Den syvende person i rĂŠkken var meget, meget langsom – sĂ„dan er det altid! Jeg har set pĂ„ en masse kode. Jeg kiggede pĂ„, hvem der skrev hvad, uden undtagelser, jeg kiggede ind i deres kode, gennemgik dem alle, og jeg fortsatte stadig med at skrive mere, end nogen af dem. Denne tilgang virker ikke sĂ„ godt med folk. Nogle kan ikke lide det. Og nĂ„r de ikke kan hĂ„ndtere det, opstĂ„r der alle mulige klager. For eksempel blev jeg engang bedt om at stoppe med at skrive kode, fordi jeg skriver for meget kode, og det truede teamet. Det lĂžd for mig som en joke: Hvis hele resten af teamet forsvinder, og jeg fortsĂŠtter med at skrive kode, vil du kun miste halvdelen af teamet. PĂ„ den anden side, hvis jeg fortsĂŠtter med at skrive kode, og du mister halvdelen af teamet – det lyder som meget dĂ„rlig ledelse. Jeg har aldrig tĂŠnkt sĂ„ meget over det, aldrig talt om det, men det var alligevel et sted i mit sind. En tanke, der kĂžrte rundt i baghovedet: "Er I alle sammen pĂ„ spĂžg?". SĂ„ den stĂžrste udfordring var mig og mine relationer til folk. Nu forstĂ„r jeg mig selv meget bedre, jeg har vĂŠret teamleder for programmĂžrer i lang tid, og nu siger jeg direkte til folk: Du ved, jeg er sĂ„dan, som jeg er, og I bliver nĂždt til at hĂ„ndtere det – er det okay, at jeg stĂ„r her? Og nĂ„r de har lĂŠrt at hĂ„ndtere det, sĂ„ fungerer det hele. Jeg er jo hverken dĂ„rlig eller god, jeg har ikke dĂ„rlige intentioner eller egoistiske strĂŠben, det er bare min essens, og man mĂ„ finde en mĂ„de at leve med det pĂ„.

Andrey: For nylig er alle begyndt at tale om selvbevidsthed for indadvendte og generelt om blĂžde fĂŠrdigheder. Hvad kan man sige om det?

CliffJa, det var en forstĂ„else og en lektie, jeg fik ud af min skilsmisse med min kone. Hvad jeg fik ud af skilsmissen – det var en forstĂ„else af mig selv. SĂ„dan begyndte jeg at forstĂ„ andre mennesker. ForstĂ„, hvordan denne interaktion fungerer. Det fĂžrte til opdagelser en efter en. Der kom en bevidsthed om, hvem jeg er, og hvad jeg reprĂŠsenterer. Hvad jeg gĂžr: enten er jeg optaget af opgaven, eller jeg undgĂ„r konflikten, eller noget andet – og et sĂ„dant niveau af selvbevidsthed hjĂŠlper virkelig med at holde sig selv i skak. Efter dette gĂ„r alt meget lettere. En ting, jeg har opdaget ikke kun hos mig selv, men ogsĂ„ hos andre programmĂžrer – er umuligheden af at verbalisere tanker, nĂ„r man er under fĂžlelsesmĂŠssig stress. For eksempel, du sidder og koder, er i en flowtilstand, og sĂ„ kommer nogen lĂžbende og begynder at skrige hysterisk, at noget er brudt sammen, og nu vil man tage drastiske foranstaltninger. Og du kan ikke sige Ă©t ord, fordi du er i en tilstand af fĂžlelsesmĂŠssig stress. Den viden, man har erhvervet, gĂžr det muligt at forberede sig pĂ„ dette Ăžjeblik, opleve det, og gĂ„ videre til en tilbagetrĂŠkningsplan, hvorefter man kan gĂžre noget. SĂ„ ja, nĂ„r man begynder at forstĂ„, hvordan det hele fungerer – er det en kĂŠmpe livsĂŠndrende begivenhed. 
Jeg kunne ikke selv finde de rigtige ord, men jeg husker sekvensen af handlinger. Essensen er, at denne reaktion er lige sĂ„ fysisk som den er verbal, og du har brug for plads. En sĂ„dan plads, i zen-forstand. Det er prĂŠcis det, der skal forklares, og sĂ„ straks trĂŠde til side – fysisk trĂŠde til side. NĂ„r jeg er stille med ord, kan jeg bearbejde situationen i forhold til fĂžlelser. Som adrenalinen nĂ„r hjernen, skifter det dig til "fight or flight"-tilstand, sĂ„ kan du ikke sige noget, nej – nu er du en idiot, en punchline-ingeniĂžr, ude af stand til at give et vĂŠrdigt svar eller stoppe angrebet, og angriberen kan frit angribe igen og igen. Man skal fĂžrst blive sig selv igen, genvinde kontrollen, komme ud af "fight or flight"-tilstand.

Og derfor er der behov for et verbalt rum. Bare et frit rum. Hvis man overhovedet skal sige noget, kan man netop hĂŠvde dette, og sĂ„ gĂ„ ud og finde sit "rum": gĂ„ en tur i parken, lĂ„se sig inde i bruseren – det er ligegyldigt. Det vigtigste er at koble midlertidigt fra den situation. SĂ„ snart du kobler fra, selv i et par sekunder, kommer kontrollen tilbage, og du begynder at tĂŠnke klart. "Godt, jeg er ikke nogen idiot, jeg laver ikke dumme ting, jeg er et ret nyttigt menneske." SĂ„ snart du kan overbevise dig selv om dette, er det tid til at gĂ„ videre til nĂŠste trin: forstĂ„, hvad der skete. Du blev angrebet, angrebet kom fra et uventet sted, det var en usportslig baghold. Det er dĂ„rligt. NĂŠste skridt er at forstĂ„, hvorfor angriberen havde brug for det. Virkelig, hvorfor? MĂ„ske fordi han selv er rasende? Hvorfor er han rasende? For eksempel fordi han selv har fejlet og ikke kan tage ansvar? PĂ„ den mĂ„de skal man forsigtigt bearbejde hele situationen. Men for dette krĂŠves der plads til manĂžvrering, verbalt rum. Det fĂžrste skridt er at bryde det verbale kontakt. GĂ„ vĂŠk fra ords diskussion. Annuller det, gĂ„ hurtigt vĂŠk. Hvis det er en telefonopkald – lĂŠg simpelthen rĂžret pĂ„ – det er en fĂŠrdighed, jeg har lĂŠrt fra mine samtaler med min tidligere kone. Hvis samtalen ikke fĂžrer til noget godt, sĂ„ sig bare "farvel" og lĂŠg rĂžret pĂ„. PĂ„ den anden side siger de: "bla-bla-bla", og du svarer: "aha, farvel!" og lĂŠgger pĂ„. Du stopper simpelthen samtalen. Fem minutter senere, nĂ„r din evne til at tĂŠnke klart kommer tilbage, er du lidt kĂžlet ned, og det bliver muligt at overveje, hvad der egentlig skete og hvad der vil ske nĂŠste gang. Og begynde at formulere et gennemtĂŠnkt svar i stedet for blot at reagere ud fra fĂžlelser. For mig var gennembruddet i selvbevidsthed netop det, at jeg i tilfĂŠlde af fĂžlelsesmĂŠssigt stress ikke kan tale. At komme ud af denne tilstand, overveje og planlĂŠgge hvordan man skal svare og kompensere for problemer – det er de rigtige skridt, nĂ„r man ikke kan tale. Den enkleste mĂ„de er at flygte fra situationen, hvor fĂžlelsesmĂŠssigt stress opstĂ„r, og simpelthen stoppe med at deltage i dette stress. Efter dette genvinder du evnen til at tĂŠnke, nĂ„r du kan tĂŠnke, og mulighederne for at tale osv.

Faktisk forsĂžger modpartens advokat at gĂžre dette med dig i retten – nu er det klart, hvorfor. Fordi han har mulighed for at presse dig til et punkt, hvor du ikke engang kan sige dit eget navn, for eksempel. I ordets mest direkte forstand, kan du ikke tale. Hvis du oplever dette og ved, at du vil vĂŠre et sted, hvor der er verbale kampe, et sted som retten, sĂ„ kan du tage din advokat med. Advokaten vil beskytte dig og stoppe den verbale angreb, og han vil gĂžre det pĂ„ en helt lovlig mĂ„de, og du vil fĂ„ dit tabte zenrum tilbage. For eksempel, jeg mĂ„tte et par gange ringe til familien, dommeren var ganske venlig, men modpartens advokat skreg og skreg af mig, jeg kunne ikke selv fĂ„ et ord ind. I sĂ„danne tilfĂŠlde fungerer det bedst for mig at bruge en mĂŠgler. MĂŠgleren stopper det tryk, der strĂžmmer over dig som en konstant strĂžm, du genfinder det nĂždvendige zenrum, og sammen med det vender evnen til at tale tilbage. Dette er et helt omrĂ„de af viden, hvor man skal lĂŠre meget, opdage meget inden i sig selv, og alt dette fĂžrer til hĂžjtstĂ„ende strategiske beslutninger, der varierer fra person til person. Nogle har ikke de omtalte problemer, typisk har folk, der professionelt arbejder med salg, ikke disse problemer. Alle disse mennesker, der lever af ord – kendte sangere, digtere, religiĂžse ledere og politikere, de har altid noget at sige. De har ikke sĂ„danne problemer, men jeg har.

Andrey: Det var... uventet. Godt, vi har allerede snakket en del, og det er tid til at afslutte dette interview. Vi ses absolut pÄ konferencen, og vi kan fortsÊtte denne dialog. Vi ses pÄ Hydra!

Du kan fortsÊtte samtalen med Cliff ved konferencen Hydra 2019, der finder sted den 11.-12. juli 2019 i Sankt Petersborg. Han kommer med et foredrag «The Azul Hardware Transactional Memory experience». Billetter kan kÞbes pÄ den officielle hjemmeside.

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster