Cliff Click â CTO of 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 the age of 15 (Pascal for TRS Z-80)! He is best 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 contributed to Java becoming one of the key modern software platforms. Later, Cliff helped Azul Systems build an 864-core mainframe running pure Java software that supported GC pauses on a 500-gigabyte heap within 10 milliseconds. Overall, Cliff has managed to work on all aspects of the JVM.
Â
This Hub post is a large interview with Cliff. We will discuss the following topics:
- Transitioning to low-level optimizations
- How to do a large refactoring
- Cost model
- Learning low-level optimizations
- Practical examples of performance improvements
- Why create your own programming language
- Career of a performance engineer
- Technical challenges
- A little about register allocation and multithreading
- The biggest challenge in life
The interviewers are:
- Andrei Sataryn from Amazon Web Services. Throughout his career, he has worked on a variety of projects: testing the distributed NewSQL database at Yandex, a cloud detection system at Kaspersky Lab, a multiplayer game at Mail.ru, and a currency pricing service at Deutsche Bank. He is interested in testing large-scale backend and distributed systems.
- Vladimir Sitnikov from Netcracker. For ten years, he has been working on the performance and scalability of NetCracker OS â software used by telecom operators to automate network management processes and network equipment. He is passionate about the performance of Java and Oracle Database. The author of over a dozen performance improvements in the official PostgreSQL JDBC driver.
Transitioning to low-level optimizations
Andrei: You are a well-known figure in the world of JIT compilation, Java, and performance work in general, right?Â
Cliff: That's right!
Andrei: Let's start with general questions about working on performance. What do you think about the choice between high-level and low-level optimizations such as working at the CPU level?
Cliff: Her er alt enkelt. Den raskeste koden er den som aldri kjĂžres. Derfor mĂ„ man alltid starte pĂ„ et hĂžyt nivĂ„ og jobbe med algoritmer. En bedre O-notasjon vil slĂ„ en dĂ„rligere O-notasjon, med mindre det kommer inn store konstanter. LavnivĂ„ting kommer alltid sist. Som regel, hvis du har optimalisert hele resten av stakken godt, og det fortsatt er noe interessant igjen â sĂ„ er det lavt nivĂ„. Men hvordan begynner du pĂ„ et hĂžyt nivĂ„? Hvordan vet du at du har gjort nok arbeid pĂ„ hĂžyt nivĂ„? Vel... ingen mĂ„te. Det finnes ingen ferdige oppskrifter. Du mĂ„ forstĂ„ problemet, bestemme deg for hva du skal gjĂžre (for ikke Ă„ ta unĂždvendige skritt senere), og sĂ„ kan du ta frem profilereren som kan si noe nyttig. PĂ„ et tidspunkt forstĂ„r du selv at du har blitt kvitt unĂždvendige ting, og det er pĂ„ tide Ă„ ta for seg finjusteringen pĂ„ lavt nivĂ„. Dette er definitivt en spesiell type kunst. Mange mennesker gjĂžr unĂždvendige ting, men de jobber sĂ„ raskt at de ikke har tid til Ă„ tenke pĂ„ ytelse. Men det varer til spĂžrsmĂ„let blir presserende. Vanligvis er 99% av tiden ingen interessert i hva jeg driver med, helt til et viktig element dukker opp pĂ„ den kritiske veien, som noen bryr seg om. Og sĂ„ begynner alle Ă„ spĂžrre hvorfor det ikke fungerte perfekt fra starten av. Generelt sett er det alltid noe Ă„ forbedre i ytelsen. Men 99% av tiden har du ikke ledetrĂ„der! Du prĂžver bare Ă„ fĂ„ noe til Ă„ fungere, og i lĂžpet av det forstĂ„r du hva som er viktig. Du kan aldri vite pĂ„ forhĂ„nd at denne biten mĂ„ vĂŠre perfekt, sĂ„ i bunn og grunn mĂ„ du vĂŠre perfekt i alt. Og det er umulig, og du gjĂžr ikke det. Det er alltid masse ting Ă„ fikse â og det er helt normalt.
How to do a large refactoring
Andrei: Hvordan jobber du med ytelsen? Dette er jo et gjennomgÄende problem. Har du for eksempel noen gang jobbet med problemer som oppstÄr pÄ grunn av overlappingen av mye eksisterende funksjonalitet?
Cliff: Jeg prĂžver Ă„ unngĂ„ det. Hvis jeg vet at ytelsen vil bli et problem, begynner jeg Ă„ tenke fĂžr jeg begynner Ă„ kode, spesielt pĂ„ datakonstruksjoner. Men ofte oppdager du alt dette senere. Og da mĂ„ man ta ekstreme tiltak og gjĂžre det jeg kaller «omtale og hersk»: man mĂ„ ta tak i et stort nok stykke. En del av koden mĂ„ uansett skrives om pĂ„ grunn av ytelsesproblemer eller av andre Ă„rsaker. Hva grunnen til omskrivning av koden mĂ„tte vĂŠre, er det nesten alltid bedre Ă„ skrive om et stĂžrre stykke enn et mindre stykke. PĂ„ dette tidspunktet begynner alle Ă„ skjelve av frykt: «Ă
h nei, vi kan ikke rĂžre sĂ„ mye kode!». Men i virkeligheten fungerer denne tilnĂŠrmingen nesten alltid mye bedre. Man mĂ„ umiddelbart ta tak i et stort problem, omringe det med en stor sirkel og si: alt som er inne i sirkelen, vil jeg skrive om. Grensen er mye mindre enn innholdet inni den som skal byttes ut. Og hvis en slik avgrensning gjĂžr at arbeidet inni blir perfekt â har du frie hender, gjĂžr hva du vil. SĂ„ snart du har forstĂ„tt problemet, gĂ„r omskrivingsprosessen mye enklere, sĂ„ ta en stor bit!
Samtidig, nÄr du gjÞr en omskrivning av store mengder og forstÄr at ytelse vil bli et problem, kan du begynne Ä bekymre deg for det med en gang. Vanligvis ender det opp med enkle ting som «ikke kopier data, hÄndter data pÄ en sÄ enkel mÄte som mulig, gjÞr dem mindre». I store omskrivninger er det standardmetoder for Ä forbedre ytelsen. Og de dreier seg nesten alltid om data.
Cost model
Andrei: I en av podcastene deres snakket dere om kostnadsmodeller i forhold til ytelse. Kan dere forklare hva som ment med det?
Cliff: SelvfĂžlgelig. Jeg ble fĂždt i en tid hvor prosessorens ytelse var ekstremt viktig. Og denne ĂŠraen er tilbake igjen â skjebnen er ikke uten ironi. Jeg begynte Ă„ leve i en tid med Ă„tte-bits maskiner, min fĂžrste datamaskin arbeidet med 256 bytes. Bare bytes. Alt var veldig lite. Det var nĂždvendig Ă„ telle instruksjoner, og sĂ„ snart vi begynte Ă„ bevege oss oppover i stakken av programmeringssprĂ„k, tok sprĂ„kene pĂ„ seg mer og mer. Det var Assembly, sĂ„ Basic, sĂ„ C, og C hĂ„ndterte mange detaljer, som registerallokering og instruksjonsvalg. Men alt var ganske forstĂ„elig, og hvis jeg laget en peker til en variabelinstans, fikk jeg en load, og kostnaden for denne instruksjonen er kjent. Maskinvaren gir et kjent antall maskinsykluser, sĂ„ hastigheten pĂ„ forskjellige operasjoner kan beregnes ved enkelt Ă„ summere opp alle instruksjonene du har tenkt Ă„ kjĂžre. Hver compare/test/branch/call/load/store kunne legges sammen, og man kunne si: her er kjĂžretiden. NĂ„r man jobber med Ă„ forbedre ytelsen, vil man definitivt legge merke til hva tallene tilsvarer smĂ„, varme slĂžyfer.Â
Men sĂ„ snart du bytter over til Java, Python og lignende ting, fjerner du deg veldig raskt fra lavnivĂ„maskinvaren. Hva er kostnaden for Ă„ kalle en getter i Java? Hvis JIT i HotSpot gjĂžr alt riktig, , vil det vĂŠre en load, men hvis det ikke skjer â vil det vĂŠre et funskjonskall. Siden kallet ligger pĂ„ den varme slĂžyfen, vil det oppheve alle andre optimaliseringer i denne slĂžyfen. SĂ„ den reelle kostnaden vil vĂŠre mye hĂžyere. Og man mister umiddelbart evnen til Ă„ se pĂ„ en kodebit og forstĂ„ at det ville vĂŠrt verdt Ă„ utfĂžre det i termer av prosessorens klokkefrekvens, brukt minne og cache. Alt dette blir interessant fĂžrst nĂ„r man virkelig graver ned i ytelsen.
Vi har nĂ„dd et punkt der prosessorhastighetene knapt har Ăžkt pĂ„ ti Ă„r. De gode gamle tidene er tilbake! Du kan ikke lenger forvente god ytelse i en enkelt trĂ„d. Men hvis man begynner med parallellbehandling â det er ekstremt komplisert, folk ser pĂ„ deg som om du er James Bond. Ti ganger hastighetsĂžkning skjer vanligvis der noen har oversett noe. Parallellitet krever mye arbeid. For Ă„ oppnĂ„ den nevnte ti ganger hastighetsĂžkningen mĂ„ man forstĂ„ kostnadsmodellen. Hva koster hva. Og for Ă„ gjĂžre det, mĂ„ man forstĂ„ hvordan sprĂ„ket passer med maskinvaren.
Martin Thompson fant et utmerket ord for bloggen sin ! Man mÄ forstÄ hva maskinvaren skal gjÞre, hvordan den skal gjÞre det, og hvorfor den gjÞr det den gjÞr. Ved Ä bruke denne kunnskapen er det ganske enkelt Ä begynne Ä telle instruksjoner og finne ut hvor tiden gÄr tapt. Hvis du ikke har passende opplÊring, sÞker du bare etter en svart katt i et mÞrkt rom. Jeg ser hele tiden folk som optimaliserer ytelse uten Ä ha den minste anelse om hva de driver med. De sliter kraftig og kommer seg ikke noe sted. NÄr jeg tar den samme koden, legger til et par smÄ knep og oppnÄr fem eller ti ganger hastighetsÞkning, sier de: vel, det er ikke rettferdig, vi visste allerede at du var bedre. Utrolig. Hva var det jeg... kostnadsmodellen handler om hvilket kode du skriver og hvor raskt det i snitt kjÞrer i et stÞrre bilde.
Andrei: Hvordan kan man holde sÄ mye informasjon i hodet? OppnÄs det gjennom mye erfaring, eller? Hvor fÄr man slik erfaring fra?
Cliff: Vel, min erfaring fikk jeg ikke pÄ den enkleste mÄten. Jeg programmerte i Assembly pÄ den tiden det var mulig Ä forstÄ hver eneste instruksjon. Det hÞres dumt ut, men siden den gang har jeg hatt et sett med Z80-instruksjoner i hodet mitt for alltid. Jeg husker ikke navnet pÄ folk bare et minutt etter samtalen, men jeg husker kode jeg skrev for 40 Är siden. Morsomt, det ser ut som syndromet til en «».
Learning low-level optimizations
Andrei: Finnes det en enklere mÄte Ä komme inn i dette pÄ?
Cliff: BĂ„de ja og nei. Maskinvaren vi alle bruker, har ikke endret seg sĂ„ mye i lĂžpet av denne tiden. Alle bruker x86, bortsett fra smarttelefoner med Arm. Hvis du ikke driver med hardcore embedded, har du det samme. Greit, videre. Instruksjoner har heller ikke endret seg pĂ„ hundrevis av Ă„r. Du mĂ„ gĂ„ og skrive noe i Assembly. Litt, men nok til Ă„ begynne Ă„ forstĂ„. Du smiler, men jeg mener det helt alvorlig. Du mĂ„ forstĂ„ forholdet mellom sprĂ„ket og maskinvaren. Etter dette mĂ„ du skrive litt og lage en liten leke-kompilator for et lite leke-sprĂ„k. âLekeâ betyr at det mĂ„ gjĂžres pĂ„ en rimelig tid. Den kan vĂŠre superenkel, men mĂ„ generere instruksjoner. Aktet med instruksjonsgenerering vil gi deg en forstĂ„else av kostnadsmodellen for broen mellom hĂžynivĂ„kode, som alle skriver i, og maskinkode, som kjĂžrer pĂ„ maskinvaren. Dette forholdet vil brenne seg inn i hodet ditt mens du skriver kompilatoren. Selv den enkleste kompilatoren. Etter dette kan du begynne Ă„ se pĂ„ Java, og det at den har en semantisk avgrunn som er mye dypere, og lage broene over den, som er mye vanskeligere. I Java er det mye vanskeligere Ă„ forstĂ„ om broen vĂ„r er god eller dĂ„rlig, hva som vil fĂ„ den til Ă„ kollapse og hva som ikke vil. Men du trenger et startpunkt nĂ„r du ser pĂ„ koden og forstĂ„r: âaha, denne getteren bĂžr inlinees hver gangâ. Og sĂ„ viser det seg at noen ganger gjĂžr de det, bortsett fra nĂ„r metoden blir for stor, og JIT begynner Ă„ inline alt mulig. Ytelsen i disse tilfellene kan forutsies umiddelbart. Vanligvis fungerer gettere godt, men sĂ„ ser du pĂ„ store hot loops og innser at det er noen funksjonskall der som er uklare og hva de gjĂžr. Dette er problemet med den omfattende bruken av gettere, grunnen til at de ikke inlinees â det er uklart om dette er en getter. Hvis du har en superliten kodebase, kan du bare huske det og si: dette er en getter, og dette er en setter. I en stor kodebase lever hver funksjon sitt eget liv, som ingen egentlig kjenner til. ProfileringsverktĂžyet sier at vi har mistet 24% av tiden i en eller annen loop, og for Ă„ forstĂ„ hva denne loopen gjĂžr, mĂ„ du se pĂ„ hver funksjon inni. Det er umulig Ă„ forstĂ„ det uten Ă„ studere funksjonen, og dette bremser forstĂ„elsesprosessen betydelig. Derfor bruker jeg ikke gettere og settere; jeg har nĂ„dd et nytt nivĂ„!
Hvor kan man finne en kostnadsmodell? Vel, man kan lese noe, selvfĂžlgelig... Men jeg tror den beste mĂ„ten er Ă„ handle. Lage en liten kompilator, og det vil vĂŠre den beste mĂ„ten Ă„ forstĂ„ kostnadsmodellen og fĂ„ den inn i sitt eget hode. En liten kompilator som ville vĂŠre nyttig for programmering av en mikrobĂžlgeovn â det er en oppgave for nybegynnere. Jeg mener, hvis du allerede har programmeringsevner, vil de vĂŠre tilstrekkelige. Alle disse tingene som Ă„ analysere en streng som vil vĂŠre et eller annet algebraisk uttrykk, hente ut instruksjoner for matematiske operasjoner i riktig rekkefĂžlge, ta de riktige verdiene fra registrene â det gjĂžres lett. Og mens du gjĂžr dette, vil det bli trykket inn i hjernen. Jeg tror alle vet hva en kompilator gjĂžr. Og det vil gi forstĂ„else for kostnadsmodellen.
Practical examples of performance improvements
Andrei: Hva annet bÞr man vÊre oppmerksom pÄ nÄr man jobber med ytelse?
Cliff: Datastrukturer. Forresten, jeg har ikke hatt disse Ăžktene pĂ„ lenge... . Det var morsomt, men det krevde sĂ„ mye innsats, og jeg har jo ogsĂ„ et liv! Ok, sĂ„ pĂ„ en av de store og interessante Ăžktene, "Hvor gĂ„r ytelsen din", ga jeg studentene et eksempel: To og en halv gigabyte fintech-data ble lest fra en CSV-fil, og sĂ„ mĂ„tte man telle antall solgte produkter. Vanlige tick-markedsdata. UDP-pakker, gjort om til tekstformat siden 70-tallet. Chicago Mercantile Exchange â diverse ting som olje, mais, soja og sĂ„ videre. Man mĂ„tte telle disse produktene, antall handler, gjennomsnittlig volum av transaksjoner og varer, osv. Det er ganske enkel handelsmatematikk: finne produktkoden (det er 1-2 tegn i en hash-tabell), fĂ„ summen, legge den til en av handelssett, legge til volum, legge til kostnad, og et par andre ting. Veldig enkel matematikk. Den lekeaktige implementeringen var veldig lettfattelig: alt lĂ„ i filen, jeg leste filen og gikk gjennom den, delte opp individuelle poster i Java-strenger, lette etter det nĂždvendige og la sammen i henhold til den ovenfor beskrevne matematikken. Og dette fungerer med en viss hastighet.
Med denne tilnĂŠrmingen er det Ă„penbart hva som skjer, og parallelle beregninger vil ikke hjelpe her, ikke sant? Det viser seg at man kan oppnĂ„ fem ganger bedre ytelse bare ved Ă„ velge riktige datatyper. Dette overrasker til og med erfarne programmerere! I mitt spesifikke tilfelle var fokuset at man ikke bĂžr allokere minne i den varme slĂžyfen. Vel, det er ikke hele sannheten, men generelt sett â unngĂ„ Ă„ allokere 'hver X', nĂ„r X er stort nok. NĂ„r X er to og en halv gigabyte, bĂžr man ikke allokere noe 'hver bokstav', eller 'hver linje', eller 'hver felt', ingenting av den typen. Det er akkurat dette som tar tid. Hvordan fungerer det egentlig? Tenk deg at jeg gjĂžr et kall String.split() eller BufferedReader.readLine(). Readline lager en streng fra en rekke bytes sendt over nettet, Ă©n gang for hver linje, for hver av hundre millioner linjer. Jeg henter denne linjen, analyserer den og kaster den. Hvorfor kaster jeg den â vel, jeg har jo allerede behandlet den, sĂ„ det er ferdig. SĂ„ for hver byte som leses fra disse 2.7G, vil to tegn bli skrevet inn i strengen, det vil si allerede 5.4G, og de er ikke nyttige for meg videre, sĂ„ de kastes. Hvis vi ser pĂ„ minnebĂ„ndbredden, laster vi 2.7G, som gĂ„r gjennom minnet og minnebussen i prosessoren, og deretter blir det to ganger mer sendt til strengen i minnet, og alt dette blir prosessert hver gang en ny streng opprettes. Men jeg mĂ„ jo lese den, hardwaren leser den, selv om alt senere blir prosessert. Og jeg mĂ„ skrive den, fordi jeg har opprettet en streng og cacheminnet er overfylt â cachen kan ikke romme 2.7G. SĂ„, for hver byte som leses, leser jeg to ekstra bytes og skriver to ekstra bytes, og til slutt har de et forhold pĂ„ 4:1 â slik bruker vi minnebĂ„ndbredden unĂždvendig. Og sĂ„ viser det seg at hvis jeg gjĂžr String.split() â sĂ„ gjĂžr jeg dette langt ifra for siste gang, det kan vĂŠre ytterligere 6-7 felt inne i det. Derfor fĂžrer klassisk CSV-lesekode med pĂ„fĂžlgende parsing av strenger til tap av minnebĂ„ndbredde pĂ„ rundt 14:1 sammenlignet med hva man faktisk ville ha. Hvis man slipper disse allokeringene, kan man oppnĂ„ fem ganger raskere ytelse.
Og dette er ikke sĂ„ veldig vanskelig. Hvis du ser pĂ„ koden fra riktig vinkel, blir alt ganske enkelt, sĂ„ snart du forstĂ„r essensen av problemet. Det er ikke noe poeng i Ă„ slutte Ă„ allokere minne: problemet er bare at du allokerer noe, og det dĂžr med en gang, og underveis brenner det en viktig ressurs, som her er minnebĂ„ndbredde. Og alt dette resulterer i redusert ytelse. PĂ„ x86 mĂ„ man vanligvis aktivt bruke prosessorens klokkesykluser, men her har du brent all minne mye tidligere. LĂžsningen er Ă„ redusere antallet allokeringer.Â
En annen del av problemet er at hvis du kjĂžrer en profilerer nĂ„r minnebĂ„ndbredden er oppbrukt, akkurat i det Ăžyeblikket det skjer, venter du vanligvis pĂ„ at hurtigbufferen skal returnere, fordi den er full av sĂžppelstoffene du nettopp har generert med alle disse linjene. Derfor blir hver load- eller store-operasjon treg, fordi de fĂžrer til cache-miss â hele hurtigbufferen har blitt treg, ventende pĂ„ at sĂžppel skal forlate. SĂ„ profilereren vil bare vise en varm, tilfeldig stĂžy, spredt over hele syklusen â det vil ikke vĂŠre noen separat hot-instruksjon eller sted i koden. Bare stĂžy. Og hvis du ser pĂ„ GC-syklene, vil de alle vĂŠre i Young Generation og superraske â mikrosekunder eller millisekunder maks. For alt dette minnet dĂžr umiddelbart. Du allokerer milliarder gigabyte, og den klipper dem, og klipper dem, og klipper dem igjen. Alt dette skjer veldig raskt. SĂ„ det er billige GC-sykluser, varm stĂžy over hele syklusen, men vi Ăžnsker Ă„ oppnĂ„ 5x hastighetsĂžkning. I dette Ăžyeblikket mĂ„ det klikke noe i hodet: «Hvorfor sĂ„?!». Overbelastning av minnebĂ„ndbredde vises ikke i den klassiske feilsĂžkeren; du mĂ„ kjĂžre en feilsĂžker for maskinvareressursene og se dette selv og direkte. Og indirekte kan man mistenke det fra disse tre symptomene. Det tredje symptomet er nĂ„r du ser hva du allokerer, spĂžr profilereren, og den svarer: «Du har gjort en milliard linjer, men GC jobbet gratis». SĂ„ snart dette skjer, innser du at du har for mye objekter og har brent hele minnebĂ„ndbredden. Det finnes en mĂ„te Ă„ finne ut av dette pĂ„, men den er ikke Ă„penbar.Â
Problemet ligger i datastukturen: den bare strukturen bak alt som skjer er for stor, det er 2.7G pĂ„ disken, sĂ„ det er veldig uĂžnsket Ă„ lage en kopi av denne tingen â man vil laste den direkte fra nettverksbytebufferet inn i registrene, for Ă„ unngĂ„ Ă„ lese og skrive frem og tilbake fem ganger. Dessverre gir ikke Java deg et slikt bibliotek som standard i JDK. Men det er jo trivielt, ikke sant? I bunn og grunn er dette 5-10 linjer med kode som gĂ„r til implementeringen av en egen bufferlaster for strenger, som etterligner oppfĂžrselen til strengklassen, mens det er en omslag rundt den underliggende bytebufferen. Resultatet er at du jobber nesten som om du bruker strenger, men egentlig flytter pekere til bufferen, og rĂ„byte kopieres ingen steder, og dermed gjenbrukes de samme bufferne gang etter gang, mens operativsystemet gladelig tar seg av oppgaver det er laget for, som skjult dobbel buffering av disse bytebufferne, mens du selv ikke trenger Ă„ behandle en uendelig strĂžm med unĂždvendige data. Forresten, dere forstĂ„r vel at ved arbeid med GC er det garantert at hver minnetildeling ikke vil bli sett av prosessoren etter den siste GC-syklusen? Derfor kan dette ikke vĂŠre i cachen, og sĂ„ skjer det en 100%-garantert misforstĂ„else. Ved arbeid med pekeren, tar det pĂ„ x86 1-2 klokkesykluser Ă„ lese et register fra minnet, og sĂ„ snart dette skjer, betaler du, betaler, betaler, for alle dataene er â og dette er kostnaden for minnetildeling. Den ekte kostnaden.
Med andre ord er datastrukturer det som er vanskeligst Ä endre. Og sÄ snart du innser at du har valgt feil datastruktur, som senere vil drepe ytelsen, krever det som regel en betydelig innsats Ä gjÞre det om, men hvis du ikke gjÞr det, vil det bli verre. FÞrst og fremst mÄ du tenke pÄ datastrukturer; det er viktig. De stÞrste kostnadene her ligger i de
Why create your own programming language
Andrei: Du sa at for Ă„ forstĂ„ kostnadsmodellen, mĂ„ du skrive ditt eget lille sprĂ„kâŠ
Cliff: Ikke et sprĂ„k, men en kompilator. Et sprĂ„k og en kompilator er forskjellige ting. Den viktigste forskjellen er i hodet ditt.Â
Andrei: For Þvrig, sÄ vidt jeg vet, eksperimenterer du med Ä lage egne sprÄk. Hvorfor?
Cliff: Fordi jeg kan! Jeg er delvis pensjonert, sÄ dette er hobbyen min. Jeg har alltid jobbet med Ä realisere andres sprÄk. Jeg har ogsÄ jobbet mye med kodingstil. Dessuten ser jeg problemer i andre sprÄk. Jeg ser at det finnes bedre mÄter Ä gjÞre vanlige ting pÄ. Jeg ville brukt dem. Jeg er lei av Ä se problemer med meg selv, i Java, i Python, i hvilket som helst annet sprÄk. Jeg skriver nÄ pÄ React Native, JavaScript og Elm som en hobby som ikke handler om pensjon, men om aktivt arbeid. Og jeg skriver ogsÄ i Python, og jeg vil mest sannsynlig fortsette Ä jobbe med maskinlÊring for Java-backender. Det er mange populÊre sprÄk, og alle har interessante egenskaper. Hvert sprÄk har sine styrker og man kan prÞve Ä samle alle disse funksjonene i ett. SÄ, jeg studerer interessante ting for meg, sprÄklig oppfÞrsel, og prÞver Ä finne fornuftig semantikk. Og sÄ langt gÄr det bra! For Þyeblikket sliter jeg med minnesemantikk, fordi jeg Þnsker Ä ha det slik som i C og Java, og fÄ en sterk minnemodell og minnesemantikk for laster og lagringer. Samtidig Þnsker jeg automatisk typeinferens som i Haskell. Her prÞver jeg Ä kombinere Haskell-lignende typeinferens med minne som fungerer som i C og Java. Dette har jeg jobbet med de siste 2-3 mÄnedene, for eksempel.
Andrei: Hvis du lager et sprÄk som tar de beste aspektene fra andre sprÄk, har du tenkt pÄ at noen kunne gjÞre det motsatte: ta ideene dine og bruke dem selv?
Cliff: Slik oppstĂ„r nye sprĂ„k! Hvorfor er Java likt C? Fordi C hadde en god syntaks som alle forstod, og Java ble inspirert av denne syntaksen, la til typesikkerhet, grensekontroller for tabeller, GC, og de forbedret noen ting i C. De la til sine egne. Men de ble ganske sterkt inspirert, ikke sant? Alle stĂ„r pĂ„ skuldrene til gigantene som kom fĂžr deg â slik skjer fremskritt.
Andrei: Som jeg forstÄr det, vil sprÄket ditt vÊre sikkert nÄr det gjelder minnebruk. Har du tenkt pÄ Ä implementere noe lignende lÄnekontrolleren fra Rust? Har du sett pÄ den, hva synes du om den?
Cliff: Vel, eg skrivur ĂĄ C dygd langa tĂð, við allar ĂŸessar malloc og free, og stĂœri handvirkt lĂfslengd. Vitið ĂŸið, 90-95% af handvirkri stjĂłrn ĂĄ lĂfslengd hefur sömu uppbyggingu. Og ĂŸað er mjög, mjög sĂĄrt að vinna með ĂŸetta handvirkt. Mig langar að compilerinn segði bara hvað er að gerast og hvað ĂŸĂș hefur nåð með ĂŸĂnum aðgerðum. Fyrir sumar aðgerðir gerir lĂĄnaathugunarinn ĂŸetta beint Ășr kassanum. Og hann ĂĄ lĂka að sjĂĄlfkrafa skila upplĂœsingum, skilja allt og jafnvel ekki leggja ĂĄ mig byrði að koma ĂŸeirri skilningi ĂĄ framfĂŠri. Hann ĂĄ að framkvĂŠma að minnsta kosti staðbundna flóði greiningu, og aðeins ef ĂŸað tekst ekki, ĂŸĂĄ ĂŸarf að bĂŠta við tegundarskĂœringum sem munu lĂœsa lĂfslengd â og slĂk uppbygging er mun flĂłknari en lĂĄnaathugunarinn eða Ă raun hvaða tilvistandi minni athugun. Valið milli âallt Ă lagiâ og âĂ©g skil ekki neittâ â nei, ĂŸað ĂŠtti að vera eitthvað betra.Â
SĂ„, som en person som har skrevet mye kode i C, mener jeg at stĂžtte for automatisk livstidsadministrasjon er det viktigste. Jeg er ogsĂ„ lei av hvor mye Java bruker minne, og den stĂžrste klagen er GC. NĂ„r du allokerer minne i Java, fĂ„r du ikke tilbake minnet som var lokalt i den siste GC-syklusen. I sprĂ„k med mer presis minnehĂ„ndtering skjer ikke dette. Hvis du kaller malloc, fĂ„r du umiddelbart minne som vanligvis nettopp har vĂŠrt brukt. Vanligvis gjĂžr du midlertidige ting med minnet og returnerer det umiddelbart. Og det blir umiddelbart tilbakefĂžrt til malloc-poolen, og den neste malloc-syklusen henter det igjen. Derfor reduseres faktisk minnebruk til settet av levende objekter pĂ„ et bestemt tidspunkt, pluss lekkasjer. Og hvis du ikke lekker pĂ„ en skandalĂžs mĂ„te, vil mesteparten av minnet bli liggende i hurtigbufferne og prosessoren, og det fungerer raskt. Men det krever mye manuell minnehĂ„ndtering ved hjelp av malloc og free, kalt i riktig rekkefĂžlge, pĂ„ riktig sted. Rust kan hĂ„ndtere dette riktig og i mange tilfeller gi enda bedre ytelse, siden minneforbruket reduseres til de nĂ„vĂŠrende beregningene â i motsetning til Ă„ vente pĂ„ den neste GC-syklusen som frigjĂžr minne. Som et resultat har vi fĂ„tt en veldig interessant mĂ„te Ă„ forbedre ytelsen pĂ„. Og ganske kraftig â jeg har jobbet med slike ting for databehandling for fintech, og dette kunne gi en forbedring pĂ„ omtrent fem ganger. Dette er en betydelig forbedring, spesielt i en verden hvor prosessorene ikke blir raskere, og vi fortsatt venter pĂ„ forbedringer.
Career of a performance engineer
Andrei: Jeg vil gjerne spĂžrre litt mer om karrieren generelt. Du ble kjent gjennom arbeidet pĂ„ JIT i HotSpot, og deretter gikk du til Azul â som ogsĂ„ er et JVM-selskap. Men du jobbet mer med maskinvare enn programvare. SĂ„ plutselig gikk du over til Big Data og MaskinlĂŠring, og deretter til svindeldeteksjon. Hvordan skjedde dette? Det er veldig forskjellige omrĂ„der innen utvikling.
Cliff: Jeg har holdt pĂ„ med programmering i ganske lang tid og har hatt erfaring med mange forskjellige prosjekter. Og nĂ„r folk sier: «à h, du er han som laget JIT for Java!», er det alltid morsomt. FĂžr dette jobbet jeg med en klone av PostScript â det sprĂ„ket som Apple en gang brukte for sine laserprintere. Og fĂžr det implementerte jeg Forth-sprĂ„ket. Jeg tror det felles temaet for meg er utvikling av verktĂžy. Hele livet har jeg laget verktĂžy som andre mennesker bruker til Ă„ skrive sine kule programmer. Men jeg har ogsĂ„ jobbet med utvikling av operativsystemer, drivere, kjernedebuggeverktĂžy, sprĂ„k for OS-utvikling som begynte trivielt, men etter hvert ble mer og mer kompliserte. Hovedmessig handler det fortsatt om utvikling av verktĂžy. En stor del av livet mitt gikk mellom Azul og Sun, og det handlet om Java. Men da jeg begynte med Big Data og MaskinlĂŠring, tok jeg pĂ„ meg min fine hatt og sa: «à h, nĂ„ har vi et ikke-trivielt problem, og det skjer virkelig mange interessante ting, med folk som gjĂžr noe». Dette er en flott vei for utvikling som er verdt Ă„ gĂ„.
Ja, eg elskar distribuerte databehandling. Min fĂžrste jobb var som student med C, pĂ„ et reklameprosjekt. Det var distribuerte databehandling pĂ„ Zilog Z80-brikker som samlet data for analog optisk tegngjenkjenning, utfĂžrt av en faktisk analog analyser. Det var et kult og helt unormalt tema. Men det var problemer, en del av informasjonen ble ikke gjenkjent riktig, sĂ„ det mĂ„tte hentes et bilde og vises til en person som allerede hadde lest det med Ăžynene og informerte om hva som ble sagt, og derfor var det jobber med data, og disse jobbene hadde sitt eget sprĂ„k. Det var en backend som hĂ„ndterte alt dette â fungerende parallelle Z80 med kjĂžrende vt100-terminaler â Ă©n per person, og det var en modell for parallell programmering pĂ„ Z80. En felles minnedel som alle Z80 delte innen en konfigurasjonstype «stjerne»; bĂ„de backplane og halve RAM ble delt i nettverket, med den andre halvdelen privat eller brukt til noe annet. En betydelig kompleks parallell distribuert system med delt... halv-delt minne. NĂ„r var dette... Jeg husker knapt, rundt midten av 80-tallet. Ganske lenge siden.Â
Ja, la oss si at 30 Ă„r er ganske lenge. Oppgaver knyttet til distribuerte databehandling har eksistert en god stund, folk har i lang tid kjempet med -klyster. Slike klyster ser ut som⊠For eksempel: det er Ethernet, og din raske x86 er koblet til dette Ethernet, og nĂ„ Ăžnsker du Ă„ fĂ„ fake shared memory, fordi ingen kunne da jobbe med koding av distribuerte beregninger, det var for komplisert, og derfor fantes det fake shared memory med sidetverrbeskyttelse pĂ„ x86, og hvis du skrev til denne siden, sĂ„ fortalte vi de andre prosessorene at hvis de fikk tilgang til den samme shared memory, mĂ„tte den lastes inn fra deg, og pĂ„ denne mĂ„ten oppsto noe som lignet protokollen for cachekoherens og programvaren for dette. En interessant konsept. Det virkelige problemet var naturligvis noe annet. Alt dette fungerte, men du fikk raskt ytelsesproblemer, siden ingen forsto ytelsesmodellen pĂ„ et tilstrekkelig godt nivĂ„ â hvilke minnemĂžnstre som var der, hvordan man kunne forhindre at nodene pinget hverandre uendelig, og sĂ„ videre.
I H2O har eg kome opp med dette: utviklarane sjĂžlve er ansvarlege for Ă„ avgjere kvar parallelisme finst og kvar ho ikkje gjer det. Eg har utvikla ein kodingsmodell som gjer det lett og enkelt Ă„ skrive hĂžgtytande kode. Men Ă„ skrive kode som gĂ„r sakte er vanskeleg, og den vil sjĂ„ dĂ„rleg ut. Ein mĂ„ verkeleg anstrenge seg for Ă„ skrive sakte kode; ein mĂ„ bruke utradisjonelle metoder. Saktekodar er synlege ved fĂžrste augekast. Som eit resultat blir det som oftast skriven kode som gĂ„r raskt, men ein mĂ„ takle hva ein skal gjere med delt minne. Alt dette knytar seg til store array og oppfĂžrselen der liknar pĂ„ ikkje-volatilar store array i parallell Java. Det vil seie, tenk deg at to trĂ„dar skriv til ein parallell array, den eine vinn, og den andre taper, og du veit ikkje kven som er kven. Om dei ikkje er volatile, kan rekkjefĂžlgja vere kva som helst â og dette fungerer faktisk veldig bra. Folk bryr seg verkeleg om rekkjefĂžlgja av operasjonar, dei plasserer volatile riktig og ventar pĂ„ ytelsesproblem knytt til minnet pĂ„ dei rette stadene. Ellers ville dei berre skrive kode i form av lĂžkker frĂ„ 1 til N, der N er trillionar, i hopp om at alle vanskelege tilfelle automatisk ville bli parallelle â og det fungerer ikkje. Men i H2O er det verken Java eller Scala, ein kan sjĂ„ pĂ„ det som "Java minus minus", om ein Ăžnskjer. Dette er ein veldig forstĂ„eleg programmeringsstil og liknar pĂ„ Ă„ skrive enkel kode i C eller Java med lĂžkker og array. Men samtidig kan ein handtere minne pĂ„ terabyte. Eg bruker framleis H2O. FrĂ„ tid til annan nyttar eg det i ulike prosjekt â og det er framleis det raskaste verktĂžyet, mange gonger raskare enn konkurrentane. Om du arbeider med Big Data med kolonne-data, er det veldig vanskeleg Ă„ overvinne H2O.
Technical challenges
Andrei: Kva har vore den stĂžrste utfordringa i karrieren din?
Cliff: Diskuterer vi den tekniske eller ikkje-tekniske delen av spĂžrsmĂ„let? Eg vil seie at dei stĂžrste utfordringane ikkje er tekniske.Â
NÄr det gjelder tekniske utfordringer, overvant jeg dem. Jeg vet ikke engang hva som var den stÞrste, men det var flere ganske interessante, som tok mye tid og mental kamp. Da jeg begynte i Sun, var jeg sikker pÄ at jeg skulle lage en rask kompilator, men mange seniorer sa at jeg aldri kom til Ä klare det. Men jeg gikk videre med dette, skrev kompilatoren helt opp til registerallokatoren, og den var ganske rask. Den var like rask som den moderne C1, men pÄ den tiden var allokatoren mye tregere, og nÄr jeg ser tilbake, var det et problem med store datastrukturer. Jeg trengte den for Ä lage en grafisk registerallokator, og jeg forstod ikke dilemmaet mellom kodeuttrykk og hastighet som eksisterte pÄ den tiden, og som var veldig viktig. Det viste seg at datastrukturen vanligvis oversteg stÞrrelsen pÄ cache-minnet pÄ x86-er fra den tiden, og derfor, hvis jeg fÞrst antok at registerallokatoren ville bruke 5-10 prosent av tiden i JIT-prosessen, endte det opp med Ä vÊre 50 prosent.
Tiden gikk, kompilatoren ble klarere og mer effektiv, den sluttet Ă„ generere grusom kode i flere tilfeller, og ytelsen begynte oftere Ă„ likne det som C-kompilatoren produserer. Med mindre du selvfĂžlgelig skriver noe sĂžppel som selv C ikke kan optimalisere. Hvis du skriver kode som i C, oppnĂ„r du ogsĂ„ ytelse som i C i flere tilfeller. Og jo lenger vi kom, jo oftere genererte koden resultater som asymptotisk samsvarte med C-nivĂ„, registerallokatoren begynte Ă„ likne et fullfĂžrt prosjekt... uansett om koden din kjĂžrte raskt eller sakte. Jeg fortsatte Ă„ jobbe med allokatoren for Ă„ gi bedre tildelinger. Den ble saktere og saktere, men ga stadig bedre ytelse i situasjoner der ingen andre klarte det. Jeg kunne grave meg inn i registerallokatoren, bruke en mĂ„ned pĂ„ arbeid der, og plutselig begynte hele koden Ă„ kjĂžre 5% raskere. Dette skjedde gang pĂ„ gang, og registerallokatoren ble noe som et kunstverk - alle elsket eller hatet det, og folk fra akademia stilte spĂžrsmĂ„l om "hvorfor alt gjĂžres pĂ„ denne mĂ„ten", hvorfor ikke , og hva er forskjellen. Svaret er det samme: en allokator basert pĂ„ graffarging pluss veldig nĂžye arbeid med bufferkode er likt et vĂ„pen for seier, den beste kombinasjonen som ingen kan overvinne. Og dette er ganske subtilt. Alt annet som kompilatoren gjĂžr, er ganske velkjente ting, selv om de ogsĂ„ er lĂžftet til kunstnivĂ„. Jeg har alltid gjort ting som skulle forvandle kompilatoren til et kunstverk. Men ingenting av dette var noe ekstraordinĂŠrt â bortsett fra registerallokatoren. Poenget er at man mĂ„ vĂŠre forsiktig under belastning, og hvis dette skjer (jeg kan forklare nĂŠrmere hvis det er interessant), betyr det at man kan inline mer aggressivt, uten risiko for Ă„ overskride knekkpunktet i ytelsesgrafen. PĂ„ den tiden var det mange fullskala kompilatorer, pyntet med finesser og klikkelyder, som hadde registerallokatorer, men ingen kunne gjĂžre det slik igjen.
Problemet er at dersom du legger til metoder som skal inline, og stadig Ăžker inline-omrĂ„det, sĂ„ vil settet av brukte verdier raskt overstige antallet registre, og man mĂ„ spile. Det kritiske nivĂ„et inntreffer ofte nĂ„r allocatoren gir opp, og en god kandidat for spilling stĂ„r i veien for en annen, slik at man ender opp med Ă„ spile noen helt ville ting. Verdien av inlining ligger i det at man mister en del overhead, overhead pĂ„ anrop og lagring, man kan se verdiene innenfor og kan optimalisere dem videre. Kostnaden ved inlining er at det dannes et stort antall aktive verdier, og hvis registerallocatorene mine spiler flere enn nĂždvendig, taper jeg med Ă©n gang. Derfor har de fleste allocatorer et problem: nĂ„r inlining gĂ„r over en viss grense, begynner alt Ă„ spile, og ytelsen kan gĂ„ nedover. De som implementerer kompilatoren, legger inn noen heuristikker: for eksempel for Ă„ stoppe inlining nĂ„r en viss stĂžrrelse er nĂ„dd, ettersom allokeringene vil Ăždelegge alt. Dette skaper et brudd i ytelsesgrafen â man inlineer, inlineer, ytelsen vokser sakte â og sĂ„, bang! â faller det bratt nedover fordi man har inlineet for mye. Slik har det vĂŠrt frem til Java dukket opp. Java krever mye mer inlining, sĂ„ jeg mĂ„tte lage min allocator mer aggressiv for at den skulle stabilisere seg og ikke falle. Og hvis du har inlineet for mye â begynner det Ă„ spile, men det er alltid et punkt der man sier «ingen mer spilling». Dette er en interessant observasjon og det kom til meg ganske uventet, ikke Ă„penbart, men det har gitt gode resultater. Jeg tok for meg aggressiv inlining, og det fĂžrte meg til steder hvor ytelsen til Java og C gĂ„r hĂ„nd i hĂ„nd. De er faktisk nĂŠr hvertandre â jeg kan skrive kode i Java som er betydelig raskere enn kode i C og sĂ„ videre, men i det store og hele, er de omtrent sammenlignbare. Det synes Ă„ vĂŠre en del av ĂŠren for dette â registerallocatorene som lar meg inline sĂ„ dumt som mulig. Jeg bare inlineer alt jeg kan se. SpĂžrsmĂ„let her er om allocatoren fungerer bra, og om resultatet er fornuftig fungerende kode. Dette var en stor utfordring: Ă„ forstĂ„ alt dette og fĂ„ det til Ă„ fungere.
A little about register allocation and multithreading
Vladimir: Problemer som registerallokering synes Ä vÊre et evigvarende tema. Det er interessant om det har vÊrt en idé som sÄ lovende ut, men som deretter mislyktes i praksis?
Cliff: SelvfĂžlgelig! Registerallokering er et omrĂ„de der du prĂžver Ă„ finne noen heuristikker for Ă„ lĂžse et NP-komplett problem. Og du vil aldri kunne oppnĂ„ en perfekt lĂžsning, ikke sant? Det er simpelthen umulig. Se pĂ„ Ahead of Time-kompilering â det fungerer ogsĂ„ dĂ„rlig. Her handler det om noen gjennomsnittlige tilfeller. Om typisk ytelse, sĂ„ du kan gĂ„ og mĂ„le noe du anser som god typisk ytelse â tross alt, jobber du med Ă„ forbedre den! Registerallokering er et tema som utelukkende er viet ytelse. SĂ„ snart du har den fĂžrste prototypen, fungerer den og gjĂžr det den skal, begynner arbeidet med ytelsen. Du mĂ„ lĂŠre deg Ă„ mĂ„le godt. Hvorfor er dette viktig? Hvis det finnes klare data, kan du se pĂ„ forskjellige deler og se: ah, dette hjalp her, men der brĂžt alt sammen! Det dukker opp noen gode ideer, du legger til en ny heuristikk, og plutselig begynner alt Ă„ fungere litt bedre i gjennomsnitt. Eller ikke. Jeg har hatt mange tilfeller der vi kjempet for fem prosent ytelse som skilte vĂ„r utvikling fra den forrige allokatoren. Og hver gang ser det slik ut: et sted vant vi, et annet sted tapte vi. Hvis du har gode ytelsesanalysverktĂžy, kan du finne tapende ideer og forstĂ„ hvorfor de taper. Kanskje er det bedre Ă„ la alt vĂŠre som det er, eller kanskje ta en mer seriĂžs tilnĂŠrming til finjustering, eller gĂ„ og fikse noe annet. Dette er en hel rekke ting! Jeg lagde denne kule hakken, men trenger ogsĂ„ denne, denne, og denne â og den totale kombinasjonen gir noen forbedringer. Og enkeltstĂ„ende kan mislykkes. Slik er naturen ved arbeid med ytelse av NP-komplette problemer.
Vladimir: Det fĂžles som om ting som farging i allokatorer er en oppgave som allerede er lĂžst. Vel, for dere er det lĂžst, ifĂžlge det dere forteller, sĂ„ er det egentlig verdt Ă„âŠ
Cliff: Den er ikke lĂžst som sĂ„dan. Det er op til dig at gĂžre den "lĂžst". Der findes tunge opgaver, og de skal lĂžses. NĂ„r det er gjort, er det tid til at arbejde pĂ„ ydelsen. Dette arbejde skal tages alvorligt - lave benchmarks, samle metrikker, forklare situationer, nĂ„r du gĂ„r tilbage til en tidligere version, og dit gamle hack pludselig begyndte at fungere igen (eller omvendt, stoppede). Og du mĂ„ ikke give op, fĂžr du opnĂ„r noget. Som jeg allerede har sagt, er der mange fede ideer, der ikke virkede, men i omrĂ„det for registerallokering er ideerne stort set uendelige. Du kan for eksempel lĂŠse videnskabelige publikationer. Selvom dette omrĂ„de nu bevĂŠger sig langsommere og er blevet mere klart end i sin ungdom, arbejder der stadig en uendelig mĂŠngde mennesker her, og deres ideer er alle vĂŠrd at prĂžve, de venter alle pĂ„ deres tid. Og du kan ikke sige, hvor gode de er, hvis du ikke prĂžver dem. Hvor godt de integreres med alt andet i din allokator, for allokatoren gĂžr mange ting, og nogle ideer i din specifikke allokator vil ikke fungere, mens de fungerer perfekt i en anden allokator. Den primĂŠre mĂ„de at vinde for allokatoren pĂ„ er at trĂŠkke langsomme dele uden for den primĂŠre sti og tvinge split ved grĂŠnserne af langsomme stier. SĂ„ hvis du Ăžnsker at starte GC, tage den langsomme vej, deoptimere, kaste undtagelsen, alt det der - 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 stier, men det er ikke sĂ„ vigtigt, fordi de er langsomme, og de er sjĂŠldent benyttet. For eksempel, en null-pointer - det sker aldrig, ikke? Du skal have flere veje til forskellige ting, men de skal ikke blande sig pĂ„ hovedvejen.Â
Vladimir: Hvad mener du om multikernede processorer, nÄr vi taler om tusinder af kerner? Er det nyttigt?
Cliff: Succesen med GPU'er viser, at det er ret nyttigt!
Vladimir: De er ret specialiserede. Hvad med almene processor?
Cliff: Vel, dette var forretningsmodellen til Azul. Svaret kom i en tid da folk virkelig satte pris pĂ„ forutsigbar ytelse. Det var da vanskelig Ă„ skrive parallellkode. H2O-modellen skalerer godt, men den er ikke en generell modell. Bare litt mer generell enn ved bruk av GPU. Snakker vi om kompleksiteten ved Ă„ utvikle noe slikt, eller kompleksiteten ved Ă„ bruke det? For eksempel, en interessant lĂŠrdom fra Azul, ganske uventet: smĂ„ hurtigbuffer er helt greit.Â
The biggest challenge in life
Vladimir: Hva med de ikke-tekniske utfordringene?
Cliff: Den stÞrste utfordringen var Ä ikke vÊre⊠vennlig og god mot folk. Og som et resultat, havnet jeg stadig i ekstremt konfliktfulle situasjoner. Situasjoner der jeg visste at alt gikk galt, men ikke visste hvordan jeg skulle gÄ videre med Ä lÞse disse problemene, og klarte ikke Ä hÄndtere dem. Mange langvarige problemer, som har vart i tiÄr, oppstod nettopp pÄ denne mÄten. At det finnes C1- og C2-kompilatorer i Java, er et direkte resultat av dette. Det faktum at det ikke har vÊrt flere nivÄer av kompilering i Java i ti Är, er ogsÄ et direkte resultat. Det er Äpenbart at vi trengte et slikt system, men det er ikke Äpenbart hvorfor det ikke fantes. Jeg hadde problemer med en ingeniÞr⊠eller en gruppe ingeniÞrer. For lenge siden, da jeg begynte Ä jobbe i Sun, var jeg⊠Vel, ikke bare da, jeg har alltid en mening om alt. Og jeg trodde pÄ sannheten i Ä bare ta denne sannheten min og si det rett ut. Spesielt siden jeg ofte faktisk hadde rett. Og hvis du ikke liker en slik tilnÊrming⊠spesielt hvis du Äpenbart tar feil og gjÞr noe dumt⊠Vel, fÄ mennesker kunne tolerere en slik kommunikasjonsform. Selv om noen kunne, for eksempel meg. Jeg har bygd hele livet mitt pÄ meritokratiske prinsipper. Hvis du viser meg noe som er feil, snur jeg meg umiddelbart og sier: du har sagt noe dumt. Samtidig, selvfÞlgelig, beklager jeg, og alt det der, anerkjenner fortjenester, hvis de i det hele tatt eksisterer, og gjÞr andre riktige handlinger. PÄ den andre siden har jeg faktisk rett en sjokkerende stor prosentandel av tiden. Og det fungerer ikke sÄ bra i forhold til folk. Jeg prÞver ikke Ä vÊre hyggelig, men setter spÞrsmÄl ved saken direkte. "Dette vil aldri fungere, fordi én, to og tre." Og de sier: "à h!". Det var ogsÄ andre konsekvenser, som det kanskje er best Ä hoppe over: for eksempel som fÞrte til skilsmisse fra kona og ti Är med depresjon etter det.
En utfordring er en kamp med folk, med oppfatningen av hva du kan eller ikke kan gjĂžre, hva som er viktig og hva som ikke er. Det har vĂŠrt mange utfordringer rundt kodestil. Jeg skriver fortsatt mye kode, og pĂ„ den tiden mĂ„tte jeg til og med senke tempoet, fordi jeg gjorde for mange oppgaver samtidig og gjorde det dĂ„rlig, i stedet for Ă„ fokusere pĂ„ Ă©n oppgave. Ser jeg tilbake, skrev jeg halvparten av koden til Java JIT-teamet, C2-teamet. Den neste raskeste koderen skrev halvparten sĂ„ raskt, den neste igjen enda langsommere, og det var en eksponentiell nedgang. Den syvende personen i rekken var veldig, veldig treg â sĂ„nn er det alltid! Jeg har vĂŠrt involvert i mye kode. Jeg har sett hvem som skriver hva, uten unntak, jeg har stirret pĂ„ koden deres, vurdert hver og en av dem, og jeg skrev fortsatt mer enn noen av dem. Denne tilnĂŠrmingen fungerer ikke sĂ„ bra med folk. Noen liker ikke det. Og nĂ„r de ikke klarer Ă„ hĂ„ndtere det, begynner det Ă„ komme diverse klager. For eksempel, en gang ble jeg bedt om Ă„ slutte Ă„ skrive kode, fordi jeg skrev for mye kode, og det truet teamet, og det hele hĂžrtes ut som en spĂžk for meg: hvis hele det gjenvĂŠrende teamet forsvinner, og jeg fortsetter Ă„ skrive kode, vil du bare miste halvparten av teamet. PĂ„ den annen side, hvis jeg fortsetter Ă„ skrive kode og du mister halvparten av teamet â det hĂžres ut som veldig dĂ„rlig ledelse. Jeg har aldri tenkt sĂ„ mye over det, aldri snakket om det, men det var fortsatt et sted i bakhodet mitt. I bakhodet surret tanken: «Er dere egentlig seriĂžse?». SĂ„ den stĂžrste utfordringen var meg og mine relasjoner med folk. NĂ„ forstĂ„r jeg meg selv mye bedre. Jeg har vĂŠrt teamleder for programmerere i lang tid, og nĂ„ sier jeg direkte til folk: vet du, jeg er den jeg er, og dere mĂ„ bare finne ut av det â er det greit at jeg stĂ„r her? Og nĂ„r de begynte Ă„ hĂ„ndtere det, begynte alt Ă„ fungere. Jeg er jo verken dĂ„rlig eller god, jeg har ingen dĂ„rlige intensjoner eller egoistiske ambisjoner, det er bare min natur, og man mĂ„ pĂ„ en eller annen mĂ„te leve med det.
Andrei: Nylig har alle begynt Ă„ snakke om selvbevissthet for introverte, og generelt om myke ferdigheter. Hva kan man si om dette?
Cliff: Ja, det var en forstĂ„else og en lĂŠrdom jeg fikk fra skilsmissen med min ekskone. Hva jeg lĂŠrte fra skilsmissen â var forstĂ„elsen av meg selv. SĂ„ begynte jeg Ă„ forstĂ„ andre mennesker. ForstĂ„ hvordan denne interaksjonen fungerer. Dette fĂžrte til oppdagelser, en etter en. Jeg ble klar over hvem jeg er og hva jeg stĂ„r for. Hva jeg gjĂžr: enten jeg er opptatt med oppgaven, unngĂ„r konflikt, eller noe annet â og et slikt nivĂ„ av selvbevissthet hjelper virkelig med Ă„ holde seg i sjakk. Etter dette blir alt mye enklere. En ting jeg oppdaget ikke bare om meg selv, men ogsĂ„ om andre programmerere â er umuligheten av Ă„ verbalisere tanker nĂ„r man er i en tilstand av emosjonelt stress. For eksempel, du sitter og koder, befinner deg i en flow-tilstand, og sĂ„ kommer noen og begynner Ă„ skrike i panikk om at noe er Ăždelagt, og nĂ„ vil de ta grove tiltak. Og du kan ikke si et ord fordi du er i en tilstand av emosjonelt stress. Den tilegnede kunnskapen gjĂžr at du kan forberede deg pĂ„ dette Ăžyeblikket, oppleve det og gĂ„ over til en tilbaketrekning, etter hvilket du kan begynne Ă„ handle. SĂ„ ja, nĂ„r du begynner Ă„ forstĂ„ hvordan alt dette fungerer â er det en stor livsendrende hendelse.Â
Jeg klarte selv ikke Ă„ finne de riktige ordene, men jeg husket rekkefĂžlgen av handlingene. Poenget er at denne reaksjonen er like fysisk som den er verbal, og du trenger rom. Et slikt rom, i zen-sinn. Dette er akkurat det som mĂ„ forklares, og sĂ„ mĂ„ man straks trekke seg tilbake â fysisk trekke seg tilbake. NĂ„r jeg er stille med ordene, kan jeg bearbeide situasjonen i fĂžlelser. Etter hvert som adrenalinet nĂ„r hjernen og setter deg i 'slĂ„ eller lĂžp' modus, kan du ikke si noe, nei â nĂ„ er du idiot, mĂ„l for frustrasjon, ute av stand til Ă„ gi et verdig svar eller til Ă„ i det minste stoppe angrepet, og angriperen kan fritt angripe igjen og igjen. FĂžrst mĂ„ du bli deg selv igjen, gjenvinne kontrollen, gĂ„ ut av 'slĂ„ eller lĂžp' modus.
Og for dette er det nĂždvendig med et verbalt rom. Bare et fritt rom. Hvis man i det hele tatt skal si noe, kan man nettopp si dette, og sĂ„ gĂ„ og faktisk finne seg et «rom»: gĂ„ en tur i parken, lĂ„se seg inne i dusjen â det spiller ingen rolle. Det viktigste er Ă„ midlertidig koble ut fra situasjonen. SĂ„ snart du klarer Ă„ koble ut selv bare for et par sekunder, kommer kontrollen tilbake, og du begynner Ă„ tenke klart. «Bra, jeg er jo ikke en idiot, jeg gjĂžr ikke dumme ting, jeg er en ganske nyttig person». SĂ„ snart du har klart Ă„ overbevise deg selv, er det pĂ„ tide Ă„ gĂ„ videre til neste steg: forstĂ„ hva som har skjedd. Du har blitt angrepet, angrepet kom fra et uventet hold, det var en urettferdig og feig bakhold. Dette er dĂ„rlig. Neste steg er Ă„ forstĂ„ hvorfor angriperen gjorde dette. Virkelig, hvorfor? Kanskje fordi han selv er rasende? Hvorfor er han rasende? For eksempel fordi han selv har rotet det til og ikke kan ta ansvar? PĂ„ denne mĂ„ten mĂ„ man forsiktig hĂ„ndtere hele situasjonen. Men for dette trenger man rom for manĂžvrering, et verbalt rom. Det aller fĂžrste steget er Ă„ bryte den verbale kontakten. Ă trekke seg unna diskusjonen med ord. Avbryt det, gĂ„ bort sĂ„ raskt som mulig. Hvis det er en telefonsamtale â legg bare pĂ„; det er en ferdighet jeg fikk fra kommunikasjon med min ekskone. Hvis samtalen ikke fĂžrer med seg noe bra, si bare «ha det» og legg pĂ„. PĂ„ den andre siden av telefonen: «bla-bla-bla», og du svarer: «aha, ha det!» og sĂ„ legger du pĂ„. Du bare avbryter samtalen. Fem minutter senere, nĂ„r evnen til Ă„ tenke klart kommer tilbake til deg, har du kjĂžlt deg ned litt, og det blir mulig Ă„ tenke over hva som faktisk har skjedd og hva som vil skje videre. Og begynne Ă„ formulere et gjennomtenkt svar, i stedet for bare Ă„ reagere pĂ„ fĂžlelsene. For meg var det et gjennombrudd i selvbevisstheten nettopp det at jeg ikke kan snakke i tilfelle emosjonelt stress. Ă komme ut av denne tilstanden, tenke over og planlegge hvordan man skal svare og hĂ„ndtere problemene â dette er de riktige stegene nĂ„r man ikke kan snakke. Den enkleste mĂ„ten er Ă„ rĂžmme fra situasjonen der emosjonelt stress oppstĂ„r og rett og slett slutte Ă„ delta i den stressen. Etter dette gjenfĂ„r du evnen til Ă„ tenke, nĂ„r du kan tenke, fĂ„r du muligheten til Ă„ snakke, og sĂ„ videre.
Forresten, i retten prĂžver motpartens advokat Ă„ gjĂžre dette med deg â nĂ„ er det klart hvorfor. Fordi han har muligheten til Ă„ undertrykke deg til et punkt der du ikke engang kan si navnet ditt, for eksempel. I ordets mest bokstavelige betydning, kan du ikke snakke. Hvis dette skjer med deg, og hvis du vet at du vil befinne deg i et sted der ordslagsmĂ„l blusser, et sted som retten, sĂ„ kan du komme med din egen advokat. Advokaten din vil forsvare deg og stoppe den verbale angrepet, og gjĂžre det pĂ„ lovlig vis, og du vil fĂ„ tilbake ditt tapte zen-rom. For eksempel, jeg mĂ„tte ringe familien et par ganger, dommeren var ganske vennlig om det, men motpartens advokat ropte og ropte pĂ„ meg, jeg kunne ikke engang fĂ„ inn et ord. I slike tilfeller fungerer det best for meg Ă„ bruke en megler. Megleren stanser alt dette presset som strĂžmmer mot deg kontinuerlig, du finner det nĂždvendige zen-rommet, og sammen med det kommer evnen til Ă„ snakke tilbake. Dette er et helt kunnskapsfelt der man mĂ„ lĂŠre mye, oppdage mye inni seg, og alt dette forvandles til hĂžy-nivĂ„ strategiske beslutninger, forskjellige for forskjellige mennesker. Noen har ikke de nevnte problemene, vanligvis har ikke folk som jobber profesjonelt med salg. Alle disse menneskene som tjener til livets opphold med ord â kjente sangere, poeter, religiĂžse figurer og politikere, de har alltid noe Ă„ si. De har ikke slike problemer, men jeg har dem.
Andrei: Det var⊠uventet. Flott, vi har allerede snakket ganske mye og det er pÄ tide Ä avslutte dette intervjuet. Vi ses definitivt pÄ konferansen, og vi kan fortsette denne dialogen. Vi sees pÄ Hydra!
Du kan fortsette samtalen med Cliff pÄ Hydra 2019 konferansen, som vil finne sted 11.-12. juli 2019 i Sankt Petersburg. Han vil komme med et innlegg . Billetter kan kjÞpes .
Kilde: habr.com
