Lieliska intervija ar Klifu Kliku, JIT kompilācijas Java valodā tēvu

Lieliska intervija ar Klifu Kliku, JIT kompilācijas Java valodā tēvuKlikŔķis KlikŔķis ā€” Cratus (IoT sensori procesu uzlaboÅ”anai) CTO, vairāku jaunuzņēmumu (tostarp Rocket Realtime School, Neurensic un H2O.ai) dibinātājs un lÄ«dzdibinātājs ar vairākiem veiksmÄ«giem izgājieniem. Savu pirmo kompilatoru Klifs uzrakstÄ«ja 15 gadu vecumā (Pascal priekÅ” TRS Z-80)! ViņŔ ir vislabāk pazÄ«stams ar savu darbu pie C2 Java (mezglu jÅ«rā IR). Å is kompilators pasaulei parādÄ«ja, ka JIT spēj ražot augstas kvalitātes kodu, kas bija viens no faktoriem Java kā vienas no galvenajām mÅ«sdienu programmatÅ«ras platformām raÅ”anās. Pēc tam Klifs palÄ«dzēja uzņēmumam Azul Systems izveidot 864 kodolu lieldatoru ar tÄ«ru Java programmatÅ«ru, kas 500 milisekundēs atbalstÄ«ja GC pauzes 10 gigabaitu kaudzÄ«tē. Kopumā Klifam izdevās strādāt pie visiem JVM aspektiem.

 
Å is habraposts ir lieliska intervija ar Klifu. Mēs runāsim par Ŕādām tēmām:

  • Pāreja uz zema lÄ«meņa optimizācijām
  • Kā veikt lielu pārstrukturÄ“Å”anu
  • Izmaksu modelis
  • Zema lÄ«meņa optimizācijas apmācÄ«ba
  • Praktiski piemēri veiktspējas uzlaboÅ”anai
  • Kāpēc izveidot savu programmÄ“Å”anas valodu
  • Veiktspējas inženiera karjera
  • Tehniskie izaicinājumi
  • Mazliet par reÄ£istru pieŔķirÅ”anu un daudzkodolu
  • Lielākais izaicinājums dzÄ«vē

Intervijas veic:

  • Andrejs Satarins no Amazon Web Services. Savā karjerā viņam izdevās strādāt pilnÄ«gi citos projektos: viņŔ testēja NewSQL izplatÄ«to datu bāzi Yandex, mākoņu noteikÅ”anas sistēmu Kaspersky Lab, vairāku spēlētāju spēli Mail.ru un pakalpojumu valÅ«tas cenu aprēķināŔanai Deutsche Bank. Interesē liela mēroga aizmugursistēmas un izplatÄ«to sistēmu testÄ“Å”ana.
  • Vladimirs Sitņikovs no Netcracker. Desmit gadu darbs pie NetCracker OS veiktspējas un mērogojamÄ«bas, programmatÅ«ras, ko telekomunikāciju operatori izmanto tÄ«kla un tÄ«kla aprÄ«kojuma pārvaldÄ«bas procesu automatizÄ“Å”anai. Interesē Java un Oracle Database veiktspējas problēmas. Autors vairāk nekā duci veiktspējas uzlabojumu oficiālajā PostgreSQL JDBC draiverÄ«.

Pāreja uz zema līmeņa optimizācijām

Andrejs: JÅ«s esat liels vārds JIT kompilācijas, Java un veiktspējas darba pasaulē kopumā, vai ne? 

Klints: Tas ir tā!

Andrejs: Sāksim ar dažiem vispārīgiem jautājumiem par izpildes darbu. Ko jūs domājat par izvēli starp augsta līmeņa un zema līmeņa optimizācijām, piemēram, darbu CPU līmenī?

Klints: Jā, Å”eit viss ir vienkārÅ”i. Ātrākais kods ir tas, kas nekad nedarbojas. Tāpēc vienmēr jāsāk no augsta lÄ«meņa, jāstrādā pie algoritmiem. Labāks O apzÄ«mējums pārspēs sliktāku O apzÄ«mējumu, ja vien neiejauksies dažas pietiekami lielas konstantes. Zema lÄ«meņa lietas paliek pēdējās. Parasti, ja esat pietiekami labi optimizējis pārējo savu steku un joprojām ir palicis dažas interesantas lietas, tas ir zems lÄ«menis. Bet kā sākt no augsta lÄ«meņa? Kā zināt, ka ir paveikts pietiekami augsta lÄ«meņa darbs? Nu... nekādā gadÄ«jumā. Gatavu recepÅ”u nav. Jums ir jāsaprot problēma, jāizlemj, ko jÅ«s darÄ«sit (lai turpmāk neveiktu nevajadzÄ«gas darbÄ«bas), un tad jÅ«s varat atklāt profilētāju, kas var pateikt kaut ko noderÄ«gu. Kādā brÄ«dÄ« jÅ«s pats saprotat, ka esat atbrÄ«vojies no nevajadzÄ«gām lietām un ir pienācis laiks veikt zema lÄ«meņa precizējumus. Tas noteikti ir Ä«paÅ”s mākslas veids. Ir daudz cilvēku, kas dara nevajadzÄ«gas lietas, bet pārvietojas tik ātri, ka viņiem nav laika uztraukties par produktivitāti. Bet tas ir lÄ«dz brÄ«dim, kad rodas jautājums. Parasti 99% gadÄ«jumu nevienam neinteresē tas, ko es daru, lÄ«dz brÄ«dim, kad uz kritiskā ceļa atnāk kāda svarÄ«ga lieta, kas nevienam nerÅ«p. Un Å”eit visi sāk jÅ«s ņurdēt par to, "kāpēc tas jau no paÅ”a sākuma nedarbojās perfekti." Kopumā sniegumā vienmēr ir ko uzlabot. Bet 99% gadÄ«jumu jums nav potenciālo pirkumu! JÅ«s vienkārÅ”i mēģināt kaut ko panākt, un Å”ajā procesā jÅ«s saprotat, kas ir svarÄ«gi. Nekad nevar zināt iepriekÅ”, ka Å”im gabalam ir jābÅ«t perfektam, tāpēc patiesÄ«bā jābÅ«t perfektam it visā. Bet tas nav iespējams, un jÅ«s to nedariet. Vienmēr ir jālabo daudzas lietas ā€“ un tas ir pilnÄ«gi normāli.

Kā veikt lielu pārstrukturÄ“Å”anu

Andrejs: Kā jÅ«s strādājat pie izrādes? Tā ir transversāla problēma. Piemēram, vai jums kādreiz ir nācies strādāt pie problēmām, kas rodas no daudzu esoÅ”o funkcionalitātes krustojuma?

Klints: Es cenÅ”os no tā izvairÄ«ties. Ja es zinu, ka veiktspēja bÅ«s problēma, es par to domāju, pirms sāku kodēt, jo Ä«paÅ”i attiecÄ«bā uz datu struktÅ«rām. Bet bieži jÅ«s to visu atklājat ļoti vēlāk. Un tad ir jāķeras pie galējiem pasākumiem un jādara tas, ko es saucu par ā€œpārrakstÄ«t un iekarotā€: jāpatver pietiekami liels gabals. Daļa koda joprojām bÅ«s jāpārraksta veiktspējas problēmu vai citu iemeslu dēļ. NeatkarÄ«gi no koda pārrakstÄ«Å”anas iemesla gandrÄ«z vienmēr ir labāk pārrakstÄ«t lielāku gabalu nekā mazāku gabalu. Å ajā brÄ«dÄ« visi sāk kratÄ«ties no bailēm: "Ak, Dievs, tu nevari pieskarties tik daudz kodam!" Bet patiesÄ«bā Ŕī pieeja gandrÄ«z vienmēr darbojas daudz labāk. Nekavējoties jāuzņemas liela problēma, jānovelk ap to liels aplis un jāsaka: es pārrakstÄ«Å”u visu apļa iekÅ”ienē. Apmale ir daudz mazāka nekā saturs tajā, kas ir jānomaina. Un, ja Ŕāda robežu novilkÅ”ana ļauj perfekti paveikt darbu iekŔā, rokas ir brÄ«vas, dari, ko gribi. Kad esat sapratis problēmu, pārrakstÄ«Å”anas process ir daudz vienkārŔāks, tāpēc ņemiet vērā!
Tajā paŔā laikā, kad veicat lielu pārrakstÄ«Å”anu un saprotat, ka veiktspēja bÅ«s problēma, varat nekavējoties sākt par to uztraukties. Tas parasti pārvērÅ”as par vienkārŔām lietām, piemēram, ā€œnekopējiet datus, pārvaldiet datus pēc iespējas vienkārŔāk, padariet tos mazusā€. Lielos pārrakstÄ«jumos ir standarta veidi, kā uzlabot veiktspēju. Un tie gandrÄ«z vienmēr ir saistÄ«ti ar datiem.

Izmaksu modelis

Andrejs: vienā no aplādes apraidiem jūs runājāt par izmaksu modeļiem produktivitātes kontekstā. Vai varat paskaidrot, ko jūs ar to domājāt?

Klints: Noteikti. Esmu dzimis laikmetā, kad procesora veiktspēja bija ārkārtÄ«gi svarÄ«ga. Un Å”is laikmets atkal atgriežas ā€“ liktenis nav bez ironijas. Es sāku dzÄ«vot astoņu bitu maŔīnu laikos; mans pirmais dators strādāja ar 256 baitiem. TieÅ”i baiti. Viss bija ļoti mazs. NorādÄ«jumi bija jāskaita, un, kad mēs sākām virzÄ«ties uz augÅ”u programmÄ“Å”anas valodu kaudze, valodas ieguva arvien vairāk. Bija Assembler, tad Basic, tad C, un C rÅ«pējās par daudzām detaļām, piemēram, reÄ£istru pieŔķirÅ”anu un instrukciju atlasi. Bet tur viss bija diezgan skaidrs, un, ja es uzrādÄ«tu rādÄ«tāju uz mainÄ«gā lieluma gadÄ«jumu, es iegÅ«tu slodzi, un Ŕīs instrukcijas izmaksas ir zināmas. AparatÅ«ra rada noteiktu skaitu maŔīnas ciklu, tāpēc dažādu lietu izpildes ātrumu var aprēķināt, vienkārÅ”i saskaitot visas instrukcijas, kuras jÅ«s gatavojaties palaist. Katru salÄ«dzinājumu/pārbaudi/nozari/zvanu/ielādÄ“Å”anu/veikalu var saskaitÄ«t un teikt: tas ir izpildes laiks jums. Strādājot pie veiktspējas uzlaboÅ”anas, noteikti pievērsÄ«siet uzmanÄ«bu tam, kādi skaitļi atbilst maziem karstajiem cikliem. 
Bet, tiklÄ«dz jÅ«s pārejat uz Java, Python un lÄ«dzÄ«gām lietām, jÅ«s ļoti ātri attālināsit no zema lÄ«meņa aparatÅ«ras. Cik maksā getter izsaukÅ”ana Java? Ja HotSpot JIT ir pareiza iekļauts, tas tiks ielādēts, bet, ja tas to nedarÄ«ja, tas bÅ«s funkcijas izsaukums. Tā kā zvans notiek karstajā cilpā, tas ignorēs visas pārējās optimizācijas Å”ajā ciklā. Tāpēc reālās izmaksas bÅ«s daudz lielākas. Un jÅ«s uzreiz zaudējat iespēju aplÅ«kot koda fragmentu un saprast, ka mums tas jāizpilda procesora takts ātruma, atmiņas un izmantotās keÅ”atmiņas ziņā. Tas viss kļūst interesants tikai tad, ja izrādē patieŔām iekļūsti.
Tagad mēs atrodamies situācijā, kad procesora ātrums gandrÄ«z nav palielinājies desmit gadus. Vecie laiki ir atgriezuÅ”ies! JÅ«s vairs nevarat paļauties uz labu viena vÄ«tnes veiktspēju. Bet, ja pēkŔņi nokļūstat paralēlajā skaitļoÅ”anā, tas ir neticami grÅ«ti, visi uz jums skatās kā uz Džeimsu Bondu. DesmitkārtÄ«gi paātrinājumi Å”eit parasti notiek vietās, kur kāds kaut ko ir saputrojis. VienlaicÄ«ba prasa daudz darba. Lai iegÅ«tu Å”o XNUMXx paātrinājumu, jums ir jāsaprot izmaksu modelis. Kas un cik tas maksā? Un, lai to izdarÄ«tu, jums ir jāsaprot, kā mēle pieguļ pamatā esoÅ”ajai aparatÅ«rai.
Martins Tompsons savam emuāram izvēlējās lielisku vārdu Mehāniskā simpātija! Jums ir jāsaprot, ko aparatÅ«ra darÄ«s, kā tieÅ”i tā to darÄ«s un kāpēc tā dara to, ko tā dara. Izmantojot to, ir diezgan viegli sākt skaitÄ«t norādÄ«jumus un izdomāt, kur paiet izpildes laiks. Ja jums nav atbilstoÅ”as ā€‹ā€‹apmācÄ«bas, jÅ«s vienkārÅ”i meklējat melnu kaÄ·i tumŔā telpā. Es redzu cilvēkus, kas visu laiku optimizē veiktspēju un kuriem nav ne jausmas, ko viņi dara. Viņi daudz cieÅ” un negÅ«st lielu progresu. Un, kad es paņemu to paÅ”u koda fragmentu, ieslÄ«dēju pāris mazos uzlauÅ”anas un paātrinu piecas vai desmit reizes, viņi saka: nu, tas nav godÄ«gi, mēs jau zinājām, ka tu esi labāks. ApbrÄ«nojami. Par ko es runāju... izmaksu modelis ir par to, kādu kodu tu raksti un cik ātri tas darbojas vidēji lielajā attēlā.

Andrejs: Un kā var noturēt galvā tādu apjomu? Vai tas tiek panākts ar lielāku pieredzi, vai? No kurienes tāda pieredze?

Klints: Nu, es nesaņēmu savu pieredzi vieglākajā veidā. Es ieprogrammēju Assembly tajos laikos, kad jÅ«s varējāt saprast katru instrukciju. Stulbi izklausās, bet kopÅ” tā laika Z80 instrukciju komplekts vienmēr ir palicis galvā, atmiņā. Es neatceros cilvēku vārdus minÅ«tes laikā pēc sarunas, bet atceros kodu, kas rakstÄ«ts pirms 40 gadiem. Tas ir smieklÄ«gi, tas izskatās pēc sindroma"idiots zinātnieks'.

Zema līmeņa optimizācijas apmācība

Andrejs: Vai ir kāds vieglāks veids, kā iekļūt?

Klints: Jā un nē. AparatÅ«ra, ko mēs visi izmantojam, laika gaitā nav tik daudz mainÄ«jusies. Visi izmanto x86, izņemot Arm viedtālruņus. Ja jÅ«s neveicat kaut kādu stingru iegulÅ”anu, jÅ«s darāt to paÅ”u. Labi, nākamais. Instrukcijas arÄ« nav mainÄ«juŔās gadsimtiem ilgi. Jums jāiet un jāieraksta kaut kas Asamblejā. Nav daudz, bet pietiekami, lai sāktu saprast. JÅ«s smaidāt, bet es runāju pilnÄ«gi nopietni. Jums ir jāsaprot valodas un aparatÅ«ras atbilstÄ«ba. Pēc tam jums jāiet un jāraksta nedaudz un jāuztaisa rotaļlietu kompilators mazai rotaļlietu valodai. Rotaļlietai lÄ«dzÄ«gais nozÄ«mē, ka tā ir jāizgatavo saprātÄ«gā laika posmā. Tas var bÅ«t ļoti vienkārÅ”s, taču tam ir jāģenerē norādÄ«jumi. Instrukcijas Ä£enerÄ“Å”ana palÄ«dzēs izprast izmaksu modeli tiltam starp augsta lÄ«meņa kodu, ko visi raksta, un maŔīnas kodu, kas darbojas aparatÅ«rā. Å Ä« sarakste tiks sadedzināta smadzenēs kompilatora rakstÄ«Å”anas laikā. Pat visvienkārŔākais kompilators. Pēc tam var sākt skatÄ«ties uz Java un to, ka tās semantiskā plaisa ir daudz dziļāka, un tiltus pāri bÅ«vēt ir daudz grÅ«tāk. Java valodā ir daudz grÅ«tāk saprast, vai mÅ«su tilts izrādÄ«jās labs vai slikts, kas liks tam sabrukt un kas nē. Bet jums ir nepiecieÅ”ams kaut kāds sākumpunkts, kurā jÅ«s skatāties uz kodu un saprotat: "jā, Å”is dabÅ«tājs ir jāiekļauj katru reizi." Un tad izrādās, ka dažreiz tas notiek, izņemot gadÄ«jumu, kad metode kļūst pārāk liela, un JIT sāk visu iekļaut. Šādu vietu sniegumu var paredzēt uzreiz. Parasti getteri darbojas labi, bet tad jÅ«s skatāties uz lielām karstajām cilpām un saprotat, ka tur plÅ«st daži funkciju izsaukumi, kas nezina, ko viņi dara. Tā ir problēma ar plaÅ”i izplatÄ«to getteru izmantoÅ”anu, iemesls, kāpēc tie nav iekļauti, ir tas, ka nav skaidrs, vai tie ir getteri. Ja jums ir ļoti maza koda bāze, varat to vienkārÅ”i atcerēties un pēc tam pateikt: Å”is ir ieguvējs, un Å”is ir iestatÄ«tājs. Lielajā kodu bāzē katra funkcija dzÄ«vo savu vēsturi, kas kopumā nevienam nav zināma. Profilētājs saka, ka mēs zaudējām 24% laika kādā cilpā, un, lai saprastu, ko Ŕī cilpa dara, mums ir jāaplÅ«ko katra funkcija iekÅ”pusē. To nav iespējams saprast, neizpētot funkciju, un tas nopietni palēnina izpratnes procesu. Tāpēc es neizmantoju getterus un seterus, esmu sasniedzis jaunu lÄ«meni!
Kur iegÅ«t izmaksu modeli? Nu ko, protams, var izlasÄ«t... Bet es domāju, ka vislabākais veids ir rÄ«koties. Neliela kompilatora izveide bÅ«s labākais veids, kā izprast izmaksu modeli un iekļaut to savā galvā. Neliels kompilators, kas bÅ«tu piemērots mikroviļņu programmÄ“Å”anai, ir iesācēja uzdevums. Nu, es domāju, ja jums jau ir programmÄ“Å”anas prasmes, tad ar to vajadzētu pietikt. Visas Ŕīs lietas, piemēram, virknes parsÄ“Å”ana, kas jums ir kā sava veida algebriskā izteiksme, matemātisko darbÄ«bu instrukciju izvilkÅ”ana no turienes pareizā secÄ«bā, pareizo vērtÄ«bu ņemÅ”ana no reÄ£istriem - tas viss tiek darÄ«ts uzreiz. Un, kamēr jÅ«s to darÄ«sit, tas tiks ierakstÄ«ts jÅ«su smadzenēs. Es domāju, ka visi zina, ko dara kompilators. Un tas sniegs izpratni par izmaksu modeli.

Praktiski piemēri veiktspējas uzlaboÅ”anai

Andrejs: Kam vēl bÅ«tu jāpievērÅ” uzmanÄ«ba, strādājot pie produktivitātes?

Klints: Datu struktÅ«ras. Starp citu, jā, es jau sen neesmu mācÄ«jis Ŕīs nodarbÄ«bas... RaÄ·eÅ”u skola. Tas bija jautri, bet tas prasÄ«ja daudz pūļu, un man arÄ« ir dzÄ«ve! LABI. Tāpēc vienā no lielajām un interesantajām nodarbÄ«bām ā€œKur paliek jÅ«su sniegumsā€ es studentiem sniedzu piemēru: no CSV faila tika nolasÄ«ti divarpus gigabaiti fintech datu, un pēc tam viņiem bija jāaprēķina pārdoto produktu skaits. . Regulāri ērču tirgus dati. UDP paketes, kas pārveidotas teksta formātā kopÅ” 70. gadiem. Čikāgas preču birža ā€“ visādas lietas, piemēram, sviests, kukurÅ«za, sojas pupiņas, tādas lietas. Vajadzēja saskaitÄ«t Å”os produktus, darÄ«jumu skaitu, vidējo naudas lÄ«dzekļu un preču kustÄ«bas apjomu utt. Tā ir diezgan vienkārÅ”a tirdzniecÄ«bas matemātika: atrodiet produkta kodu (tas ir 1ā€“2 rakstzÄ«mes hash tabulā), iegÅ«stiet summu, pievienojiet to vienai no tirdzniecÄ«bas kopām, pievienojiet apjomu, pievienojiet vērtÄ«bu un dažas citas lietas. Ä»oti vienkārÅ”a matemātika. Rotaļlietas realizācija bija ļoti vienkārÅ”a: viss ir failā, es izlasu failu un pārvietojos pa to, sadalot atseviŔķus ierakstus Java virknēs, meklējot tajās nepiecieÅ”amās lietas un saskaitot tos pēc iepriekÅ” aprakstÄ«tās matemātikas. Un tas darbojas ar nelielu ātrumu.

Izmantojot Å”o pieeju, ir skaidrs, kas notiek, un paralēlā skaitļoÅ”ana nepalÄ«dzēs, vai ne? Izrādās, ka pieckārtÄ«gu veiktspējas pieaugumu var panākt, vienkārÅ”i izvēloties pareizās datu struktÅ«ras. Un tas pārsteidz pat pieredzējuÅ”us programmētājus! Manā konkrētajā gadÄ«jumā triks bija tāds, ka nevajadzētu veikt atmiņas pieŔķirÅ”anu karstā cilpā. Nu, tā nav visa patiesÄ«ba, bet kopumā - nevajadzētu izcelt ā€œvienu reizi Xā€, ja X ir pietiekami liels. Ja X ir divarpus gigabaiti, jums nevajadzētu pieŔķirt neko ā€œvienu reizi burtāā€, ā€œvienu reizi rindāā€, vai ā€œvienu reizi laukāā€, kaut ko tamlÄ«dzÄ«gu. Å eit tiek pavadÄ«ts laiks. Kā tas vispār darbojas? Iedomājieties, ka es zvanu String.split() vai BufferedReader.readLine(). Readline izveido virkni no baitu kopas, kas tika saņemta tÄ«klā, vienu reizi katrai rindai, katrai no simtiem miljonu lÄ«niju. Es paņemu Å”o lÄ«niju, parsēju un izmetu. Kāpēc es to izmetu - labi, es to jau esmu apstrādājis, tas arÄ« viss. Tātad katram baitam, kas nolasÄ«ts no Å”iem 2.7G, rindā tiks ierakstÄ«tas divas rakstzÄ«mes, tas ir, jau 5.4G, un man tās vairs nekam nevajag, tāpēc tiek izmestas. Ja paskatās uz atmiņas joslas platumu, mēs ielādējam 2.7 G, kas iet caur atmiņu un atmiņas kopni procesorā, un tad divreiz vairāk tiek nosÅ«tÄ«ts uz atmiņā esoÅ”o lÄ«niju, un tas viss tiek nobružāts, veidojot katru jaunu lÄ«niju. Bet man tas ir jāizlasa, aparatÅ«ra to nolasa, pat ja vēlāk viss ir nobružāts. Un man tas ir jāpieraksta, jo izveidoju rindiņu un keÅ”atmiņas ir pilnas - keÅ”atmiņā nevar ievietot 2.7G. Tātad, par katru izlasÄ«to baitu es nolasu vēl divus baitus un uzrakstu vēl divus baitus, un galu galā tiem ir attiecÄ«ba 4:1 - Å”ajā attiecÄ«bā mēs tērējam atmiņas joslas platumu. Un tad izrādās, ka, ja es to darÄ«Å”u String.split() ā€“ Ŕī nav pēdējā reize, kad to daru, iekŔā var bÅ«t vēl kādi 6-7 lauki. Tātad klasiskais kods, nolasot CSV un pēc tam parsējot virknes, rada atmiņas joslas platuma zudumu aptuveni 14:1 attiecÄ«bā pret to, ko jÅ«s patiesÄ«bā vēlētos. Izmetot Ŕīs izlases, varat iegÅ«t pieckārtÄ«gu ātrumu.

Un tas nav nemaz tik grÅ«ti. Ja paskatās uz kodu no pareizā leņķa, tas viss kļūst pavisam vienkārÅ”i, tiklÄ«dz jÅ«s saprotat problēmu. Jums nevajadzētu pilnÄ«bā pārtraukt atmiņas pieŔķirÅ”anu: vienÄ«gā problēma ir tā, ka jÅ«s pieŔķirat kaut ko, un tas nekavējoties nomirst, un pa ceļam tas sadedzina svarÄ«gu resursu, kas Å”ajā gadÄ«jumā ir atmiņas joslas platums. Un tas viss noved pie produktivitātes krituma. Uz x86 jums parasti ir nepiecieÅ”ams aktÄ«vi ierakstÄ«t procesora ciklus, bet Å”eit jÅ«s sadedzinājāt visu atmiņu daudz agrāk. Risinājums ir samazināt izdalÄ«jumu daudzumu. 
Otra problēmas daļa ir tāda, ka, ja palaižat profilētāju, kad beidzas atmiņas josla, tieÅ”i tad, kad tas notiek, jÅ«s parasti gaidāt, kad keÅ”atmiņa atgriezÄ«sies, jo tā ir pilna ar tikko radÄ«tajiem atkritumiem, visas Ŕīs rindas. LÄ«dz ar to katra ielāde vai veikala darbÄ«ba kļūst lēna, jo tās noved pie keÅ”atmiņas izlaiÅ”anas ā€“ visa keÅ”atmiņa ir kļuvusi lēna, gaidot, kad to pametÄ«s atkritumi. Tāpēc profilētājs tikai rādÄ«s siltu nejauÅ”u troksni, kas izsmērēts visā cilpā - nebÅ«s atseviŔķas karstās instrukcijas vai vietas kodā. Tikai troksnis. Un, ja paskatās uz GC ciklus, tie visi ir Jaunās paaudzes un Ä«paÅ”i ātri - mikrosekundes vai milisekundes maksimums. Galu galā visa Ŕī atmiņa nomirst uzreiz. JÅ«s pieŔķirat miljardus gigabaitu, un viņŔ tos sagriež, sagriež un vēlreiz. Tas viss notiek ļoti ātri. Izrādās, ka ir lēti GC cikli, silts troksnis visa cikla garumā, bet gribam dabÅ«t 5x paātrinājumu. Å ajā brÄ«dÄ« kaut kam vajadzētu aizvērties galvā un skanēt: "kāpēc tas ir?!" Atmiņas joslas pārpilde netiek rādÄ«ta klasiskajā atkļūdotājs; jums ir jāpalaiž aparatÅ«ras veiktspējas skaitÄ«tāja atkļūdotājs un jāredz tas pats un tieÅ”i. Bet no Å”iem trim simptomiem to nevar tieÅ”i aizdomāties. TreÅ”ais simptoms ir, kad paskatās uz izcelto, pajautā profilētājam, un viņŔ atbild: "JÅ«s izveidojāt miljardu rindu, bet GC strādāja bez maksas." TiklÄ«dz tas notiek, jÅ«s saprotat, ka esat izveidojis pārāk daudz objektu un sadedzinājis visu atmiņas joslu. Ir veids, kā to noskaidrot, bet tas nav acÄ«mredzams. 

Problēma ir datu struktÅ«rā: visa notiekoŔā pamatā esoŔā tukŔā struktÅ«ra ir pārāk liela, diskā ir 2.7G, tāpēc Ŕīs lietas kopÄ“Å”ana ir ļoti nevēlama - jÅ«s vēlaties to nekavējoties ielādēt no tÄ«kla baitu bufera. reÄ£istros, lai piecas reizes nelasÄ«tu-rakstu uz rindu uz priekÅ”u un atpakaļ. Diemžēl Java pēc noklusējuma nepieŔķir jums Ŕādu bibliotēku kā daļu no JDK. Bet tas ir triviāli, vai ne? BÅ«tÄ«bā tās ir 5ā€“10 koda rindiņas, kas tiks izmantotas, lai ieviestu jÅ«su buferizēto virkņu ielādētāju, kas atkārto virkņu klases darbÄ«bu, vienlaikus apgÅ«stot pamatā esoÅ”o baitu buferi. Rezultātā izrādās, ka jÅ«s strādājat gandrÄ«z kā ar virknēm, bet patiesÄ«bā tur pārvietojas norādes uz buferi, un neapstrādātie baiti nekur netiek kopēti, un lÄ«dz ar to tie paÅ”i buferi tiek izmantoti atkal un atkal, un operētājsistēma labprāt uzņemas lietas, kurām tā ir paredzēta, piemēram, Å”o baitu buferu slēpto dubulto buferizāciju, un jÅ«s vairs negraužat nevajadzÄ«gu datu bezgalÄ«gu straumi. Starp citu, vai jÅ«s saprotat, ka strādājot ar GC, tiek garantēts, ka katrs atmiņas sadalÄ«jums pēc pēdējā GC cikla nebÅ«s redzams procesoram? Tāpēc tas viss nevar bÅ«t keÅ”atmiņā, un tad notiek 100% garantēta garām. Strādājot ar rādÄ«tāju x86, reÄ£istra atņemÅ”ana no atmiņas aizņem 1-2 pulksteņa ciklus, un tiklÄ«dz tas notiek, jÅ«s maksājat, maksājat, maksājat, jo atmiņa ir ieslēgta DEVIŅAS keÅ”atmiņas ā€“ un tās ir atmiņas pieŔķirÅ”anas izmaksas. Reālā vērtÄ«ba.

Citiem vārdiem sakot, visgrÅ«tāk ir mainÄ«t datu struktÅ«ras. Un, tiklÄ«dz jÅ«s saprotat, ka esat izvēlējies nepareizu datu struktÅ«ru, kas vēlāk samazinās veiktspēju, parasti ir daudz darāmā, taču, ja jÅ«s to nedarÄ«sit, viss pasliktināsies. Pirmkārt, jums ir jādomā par datu struktÅ«rām, tas ir svarÄ«gi. Galvenās izmaksas Å”eit attiecas uz resnajām datu struktÅ«rām, kuras sāk izmantot stilā ā€œEs nokopēju datu struktÅ«ru X datu struktÅ«rā Y, jo man labāk patÄ«k Y formaā€. Taču kopÄ“Å”anas darbÄ«ba (kas Ŕķiet lēta) faktiski izŔķiež atmiņas joslas platumu, un tur tiek aprakts viss izŔķērdētais izpildes laiks. Ja man ir milzÄ«ga JSON virkne un es vēlos to pārvērst par strukturētu POJO DOM koku vai kaut ko citu, Ŕīs virknes parsÄ“Å”ana un POJO izveidoÅ”ana un pēc tam atkal piekļūŔana POJO vēlāk radÄ«s nevajadzÄ«gas izmaksas ā€” tas ir. nav lēts. Izņemot gadÄ«jumus, kad jÅ«s daudz biežāk skraidāt ap POJO, nevis ap virkni. Tā vietā varat mēģināt atÅ”ifrēt virkni un iegÅ«t no turienes tikai to, kas jums nepiecieÅ”ams, nepārvērÅ”ot to par POJO. Ja tas viss notiek uz ceļa, no kura ir nepiecieÅ”ama maksimāla veiktspēja, jums nav POJO, jums ir kaut kā jāieraksta lÄ«nija tieÅ”i.

Kāpēc izveidot savu programmÄ“Å”anas valodu

Andrejs: Jūs teicāt, ka, lai saprastu izmaksu modeli, jums ir jāraksta sava mazā valoda...

Klints: Nevis valoda, bet kompilators. Valoda un kompilators ir divas dažādas lietas. VissvarÄ«gākā atŔķirÄ«ba ir jÅ«su galvā. 

Andrejs: Starp citu, cik man zināms, jÅ«s eksperimentējat ar savu valodu radÄ«Å”anu. Par ko?

Klints: Jo es varu! Esmu daļēji pensijā, tāpēc tas ir mans hobijs. Es visu mūžu esmu ieviesis citu cilvēku valodas. Es arÄ« daudz strādāju pie sava kodÄ“Å”anas stila. Un arÄ« tāpēc, ka redzu problēmas citās valodās. Es redzu, ka ir labāki veidi, kā darÄ«t pazÄ«stamas lietas. Un es tos izmantotu. Man vienkārÅ”i ir apnicis redzēt problēmas sevÄ«, Java, Python, jebkurā citā valodā. Es tagad rakstu React Native, JavaScript un Elm kā hobiju, kas nav saistÄ«ts ar pensionÄ“Å”anos, bet gan par aktÄ«vu darbu. Es arÄ« rakstu Python un, visticamāk, turpināŔu strādāt pie maŔīnmācÄ«Å”anās Java aizmugursistēmai. Ir daudz populāru valodu, un tām visām ir interesantas funkcijas. Katrs ir labs savā veidā, un jÅ«s varat mēģināt apvienot visas Ŕīs funkcijas. Tātad, es studēju lietas, kas mani interesē, valodas uzvedÄ«bu, mēģinu izdomāt saprātÄ«gu semantiku. Un pagaidām man tas izdodas! Å obrÄ«d cÄ«nos ar atmiņas semantiku, jo gribu, lai tā bÅ«tu kā C un Java, un dabÅ«tu spēcÄ«gu atmiņas modeli un atmiņas semantiku ielādÄ“Å”anai un veikaliem. Tajā paŔā laikā izmantojiet automātisku tipa secinājumu, piemēram, Haskell. Å eit es mēģinu sajaukt Haskell tipa secinājumus ar atmiņas darbu gan C, gan Java. Tā es, piemēram, daru pēdējos 2-3 mēneÅ”us.

Andrejs: Ja jūs veidojat valodu, kas pārņem labākus aspektus no citām valodām, vai jūs domājat, ka kāds darīs pretējo: ņems jūsu idejas un izmantos tās?

Klints: TieÅ”i Ŕādi parādās jaunas valodas! Kāpēc Java ir lÄ«dzÄ«ga C? Tā kā C bija laba sintakse, ko visi saprata, un Java iedvesmoja Ŕī sintakse, pievienojot veidu droŔību, masÄ«vu robežu pārbaudi, GC, un viņi arÄ« uzlaboja dažas lietas no C. Viņi pievienoja savas. Bet viņi bija diezgan iedvesmoti, vai ne? Ikviens stāv uz to milžu pleciem, kuri bija pirms jums - tā tiek panākts progress.

Andrejs: Kā es saprotu, jÅ«su valoda bÅ«s droÅ”a. Vai esat domājis par tādas lietas ievieÅ”anu kā aizņemties pārbaudÄ«tāju no Rust? Vai esi uz viņu skatÄ«jies, ko tu par viņu domā?

Klints: Nu, es esmu rakstÄ«jis C jau daudzus gadus, izmantojot visu Å”o malloc un bezmaksas, un manuāli pārvaldot visu mūžu. JÅ«s zināt, 90-95% no manuāli kontrolētā dzÄ«ves laika ir tāda pati struktÅ«ra. Un tas ir ļoti, ļoti sāpÄ«gi to darÄ«t manuāli. Gribētos, lai sastādÄ«tājs vienkārÅ”i pastāsta, kas tur notiek un ko ar savām darbÄ«bām panācāt. Dažām lietām aizņēmumu pārbaudÄ«tājs to dara jau no kastes. Un tai vajadzētu automātiski parādÄ«t informāciju, saprast visu un pat neapgrÅ«tināt mani ar Ŕīs izpratnes pasniegÅ”anu. Tai ir jāveic vismaz lokālā aizbēgÅ”anas analÄ«ze, un tikai tad, ja tā neizdodas, tai ir jāpievieno tipa anotācijas, kas apraksta kalpoÅ”anas laiku - un Ŕāda shēma ir daudz sarežģītāka nekā aizņemÅ”anās pārbaudÄ«tājs vai jebkurÅ” esoÅ”ais atmiņas pārbaudÄ«tājs. Izvēle starp ā€œviss ir kārtÄ«bāā€ un ā€œEs neko nesaprotuā€ - nē, ir jābÅ«t kaut kam labākam. 
Tāpēc kā cilvēks, kurÅ” ir uzrakstÄ«jis daudz koda C valodā, es domāju, ka vissvarÄ«gākais ir atbalsts automātiskai mūža kontrolei. Man arÄ« ir apnicis, cik daudz Java izmanto atmiņu, un galvenā sÅ«dzÄ«ba ir GC. PieŔķirot atmiņu Java, jÅ«s neatgÅ«sit atmiņu, kas bija vietējā pēdējā GC ciklā. Tas tā nav valodās ar precÄ«zāku atmiņas pārvaldÄ«bu. Ja zvanāt malloc, jÅ«s nekavējoties iegÅ«sit atmiņu, kas parasti tika izmantota. Parasti jÅ«s veicat dažas pagaidu darbÄ«bas ar atmiņu un nekavējoties atdodat to atpakaļ. Un tas nekavējoties atgriežas malloc baseinā, un nākamais malloc cikls to atkal izvelk. Tāpēc faktiskais atmiņas lietojums tiek samazināts lÄ«dz dzÄ«vo objektu kopumam noteiktā laikā, kā arÄ« noplÅ«dēm. Un, ja viss nenoplÅ«st pilnÄ«gi nepiedienÄ«gā veidā, lielākā daļa atmiņas nonāk keÅ”atmiņā un procesorā, un tas darbojas ātri. Bet prasa daudz manuālas atmiņas pārvaldÄ«bas ar malloc un bezmaksas zvanu pareizajā secÄ«bā, Ä«stajā vietā. RÅ«sa var pareizi tikt galā ar to un daudzos gadÄ«jumos nodroÅ”ina vēl labāku veiktspēju, jo atmiņas patēriņŔ tiek samazināts lÄ«dz paÅ”reizējam aprēķinam, nevis gaidÄ«t nākamo GC ciklu, lai atbrÄ«votu atmiņu. Rezultātā mēs ieguvām ļoti interesantu veidu, kā uzlabot veiktspēju. Un diezgan jaudÄ«gs ā€” es domāju, es darÄ«ju Ŕādas darbÄ«bas, apstrādājot fintech datus, un tas ļāva man paātrināt apmēram piecas reizes. Tas ir diezgan liels stimuls, it Ä«paÅ”i pasaulē, kur procesori nekļūst ātrāki un mēs joprojām gaidām uzlabojumus.

Veiktspējas inženiera karjera

Andrejs: Vēlos pajautāt arÄ« par karjeru kopumā. JÅ«s ieguvāt ievērojamu vietu ar savu JIT darbu HotSpot un pēc tam pārcēlāties uz Azul, kas arÄ« ir JVM uzņēmums. Bet mēs jau vairāk strādājām pie aparatÅ«ras, nevis programmatÅ«ras. Un tad viņi pēkŔņi pārgāja uz lielo datu un maŔīnmācÄ«Å”anos un pēc tam uz krāpÅ”anas atklāŔanu. Kā tas notika? Tās ir ļoti dažādas attÄ«stÄ«bas jomas.

Klints: Es programmēju diezgan ilgu laiku, un man ir izdevies apmeklēt daudzas dažādas nodarbÄ«bas. Un, kad cilvēki saka: ā€œAk, tu esi tas, kurÅ” veica JIT priekÅ” Java!ā€, tas vienmēr ir smieklÄ«gi. Bet pirms tam es strādāju pie PostScript klona ā€” valodas, ko Apple savulaik izmantoja saviem lāzerprinteriem. Un pirms tam es ieviesu Forth valodu. Manuprāt, kopējā tēma man ir rÄ«ku izstrāde. Visu mūžu esmu veidojis rÄ«kus, ar kuriem citi raksta savas forŔās programmas. Bet es piedalÄ«jos arÄ« operētājsistēmu, draiveru, kodola lÄ«meņa atkļūdotāju, OS izstrādes valodu izstrādē, kas sākās triviāli, bet laika gaitā kļuva arvien sarežģītāka. Bet galvenā tēma joprojām ir instrumentu izstrāde. Liela daļa manas dzÄ«ves pagāja starp Azul un Sun, un tā bija par Java. Bet, kad es iesaistÄ«jos Big Data un Machine Learning, es atkal uzliku savu izdomāto cepuri un teicu: "Ak, tagad mums ir nenozÄ«mÄ«ga problēma, un notiek daudz interesantu lietu un cilvēki dara lietas." Tas ir lielisks attÄ«stÄ«bas ceļŔ.

Jā, man ļoti patÄ«k izplatÄ«ta skaitļoÅ”ana. Mans pirmais darbs bija kā students C, pie reklāmas projekta. Tas tika izplatÄ«ts, izmantojot Zilog Z80 mikroshēmas, kas apkopoja datus analogajam OCR, ko ražo reāls analogais analizators. Tā bija forÅ”a un pilnÄ«gi traka tēma. Bet bija problēmas, kāda daļa netika pareizi atpazÄ«ta, tāpēc bija jāizņem bilde un jāparāda cilvēkam, kurÅ” jau varēja lasÄ«t ar acÄ«m un ziņot par to, un tāpēc bija darbi ar datiem, un Å”ie darbi bija sava valoda. Bija aizmugure, kas to visu apstrādāja - Z80s darbojās paralēli ar vt100 termināļiem, kas darbojas - viens uz cilvēku, un Z80 bija paralēlas programmÄ“Å”anas modelis. Dažas kopÄ«gas atmiņas daļas, ko koplieto visi Z80 zvaigznÄ«tes konfigurācijā; ArÄ« aizmugurējā plakne tika koplietota, un puse no RAM tika koplietota tÄ«klā, bet vēl viena puse bija privāta vai tika izmantota kaut kam citam. Sarežģīta paralēli sadalÄ«ta sistēma ar koplietotu... daļēji koplietotu atmiņu. Kad tas bija... Es pat neatceros, kaut kur 80. gadu vidÅ«. Diezgan sen. 
Jā, pieņemsim, ka 30 gadi ir diezgan sen. Problēmas, kas saistÄ«tas ar izkliedēto skaitļoÅ”anu, pastāv jau diezgan ilgu laiku, cilvēki jau sen karo ar Beowulf-kopas. Tādi klasteri izskatās... Piemēram: ir Ethernet un tavs ātrais x86 ir pieslēgts Å”im Ethernet, un tagad gribi dabÅ«t viltus koplietojamo atmiņu, jo toreiz neviens nevarēja veikt dalÄ«to skaitļoÅ”anas kodÄ“Å”anu, tas bija pārāk grÅ«ti un tāpēc tur bija viltota koplietojamā atmiņa ar aizsardzÄ«bas atmiņas lapām uz x86, un, ja jÅ«s rakstÄ«jāt uz Å”o lapu, tad mēs teicām citiem procesoriem, ka, ja viņi piekļūs tai paÅ”ai koplietotajai atmiņai, tā bÅ«s jāielādē no jums, un tādējādi kaut kas lÄ«dzÄ«gs atbalsta protokolam. parādÄ«jās keÅ”atmiņas saskaņotÄ«ba un programmatÅ«ra tam. Interesants koncepts. Patiesā problēma, protams, bija kas cits. Tas viss nostrādāja, taču ātri radās veiktspējas problēmas, jo neviens nesaprata veiktspējas modeļus pietiekami labā lÄ«menÄ« ā€“ kādi tur ir atmiņas piekļuves modeļi, kā nodroÅ”ināt, lai mezgli bezgalÄ«gi neping viens otru utt.

Tas, ko es izdomāju H2O, ir tas, ka paÅ”i izstrādātāji ir atbildÄ«gi par to, lai noteiktu, kur paralēlisms ir paslēpts un kur tas nav. Es izdomāju kodÄ“Å”anas modeli, kas padarÄ«ja augstas veiktspējas koda rakstÄ«Å”anu vieglu un vienkārÅ”u. Bet rakstÄ«t lēni darbojoÅ”os kodu ir grÅ«ti, tas izskatÄ«sies slikti. Jums nopietni jāmēģina rakstÄ«t lēnu kodu, jums bÅ«s jāizmanto nestandarta metodes. BremzÄ“Å”anas kods ir redzams no pirmā acu uzmetiena. Tā rezultātā parasti tiek rakstÄ«ts kods, kas darbojas ātri, bet jums ir jāizdomā, ko darÄ«t koplietojamās atmiņas gadÄ«jumā. Tas viss ir saistÄ«ts ar lieliem masÄ«viem, un tur darbojas lÄ«dzÄ«gi kā nepastāvÄ«gi lieli masÄ«vi paralēli Java. Es domāju, iedomājieties, ka divi pavedieni raksta paralēlā masÄ«vā, viens no tiem uzvar, bet otrs attiecÄ«gi zaudē, un jÅ«s nezināt, kurÅ” no tiem ir kurÅ”. Ja tie nav nepastāvÄ«gi, tad pasÅ«tÄ«jums var bÅ«t tāds, kādu vēlaties - un tas darbojas patieŔām labi. Cilvēkiem patieŔām rÅ«p darbÄ«bu secÄ«ba, viņi ievieto gaistoÅ”us pareizajās vietās un sagaida ar atmiņu saistÄ«tas veiktspējas problēmas pareizajās vietās. Pretējā gadÄ«jumā viņi vienkārÅ”i rakstÄ«tu kodu cilpu veidā no 1 lÄ«dz N, kur N ir daži triljoni, cerot, ka visi sarežģītie gadÄ«jumi automātiski kļūs paralēli - un tas tur nedarbojas. Bet H2O tas nav ne Java, ne Scala; ja vēlaties, varat to uzskatÄ«t par "Java mÄ«nus mÄ«nusu". Tas ir ļoti skaidrs programmÄ“Å”anas stils un ir lÄ«dzÄ«gs vienkārÅ”a C vai Java koda rakstÄ«Å”anai ar cilpām un masÄ«viem. Bet tajā paŔā laikā atmiņu var apstrādāt terabaitos. Es joprojām izmantoju H2O. Ik pa laikam to izmantoju dažādos projektos ā€“ un tā joprojām ir ātrākā lieta, desmitiem reižu ātrāka par konkurentiem. Ja veicat lielos datus, izmantojot kolonnu datus, ir ļoti grÅ«ti pārspēt H2O.

Tehniskie izaicinājumi

Andrejs: Kāds ir bijis tavs lielākais izaicinājums visā tavā karjerā?

Klints: Vai mēs apspriežam jautājuma tehnisko vai netehnisko daļu? Es teiktu, ka lielākie izaicinājumi nav tehniski. 
Kas attiecas uz tehniskajiem izaicinājumiem. Es viņus vienkārÅ”i uzvarēju. Es pat nezinu, kas bija lielākais, bet bija daži diezgan interesanti, kas prasÄ«ja diezgan daudz laika, garÄ«gas cīņas. Kad aizgāju uz Sun, biju pārliecināts, ka uztaisÄ«Å”u ātru sastādÄ«tāju, un bariņŔ senioru atbildēja, ka man tas nekad neizdosies. Bet es gāju Å”o ceļu, pierakstÄ«ju kompilatoru lÄ«dz reÄ£istra sadalÄ«tājam, un tas bija diezgan ātri. Tas bija tikpat ātrs kā mÅ«sdienu C1, taču sadalÄ«tājs toreiz bija daudz lēnāks, un, skatoties vēlāk, tā bija liela datu struktÅ«ras problēma. Man tas bija vajadzÄ«gs, lai uzrakstÄ«tu grafisko reÄ£istru sadalÄ«tāju, un es nesapratu dilemmu starp koda izteiksmÄ«gumu un ātrumu, kas pastāvēja tajā laikmetā un bija ļoti svarÄ«ga. IzrādÄ«jās, ka datu struktÅ«ra parasti pārsniedz tā laika x86s keÅ”atmiņas lielumu, un tāpēc, ja sākotnēji pieņēmu, ka reÄ£istra sadalÄ«tājs nostrādās 5-10 procentus no kopējā nervozÄ“Å”anas laika, tad patiesÄ«bā tas izrādÄ«jās 50 procenti.

Laikam ejot, kompilators kļuva tÄ«rāks un efektÄ«vāks, vairākos gadÄ«jumos pārtrauca Ä£enerēt Å”ausmÄ«gu kodu, un veiktspēja arvien vairāk sāka lÄ«dzināties C kompilatora radÄ«tajam. Ja vien, protams, neuzrakstiet kādu stulbumu, ko pat C nepaātrina. . Ja rakstÄ«sit kodu, piemēram, C, vairākos gadÄ«jumos iegÅ«sit tādu veiktspēju kā C. Un jo tālāk, jo biežāk jÅ«s dabÅ«jāt kodu, kas asimptotiski sakrita ar C lÄ«meni, reÄ£istra sadalÄ«tājs sāka izskatÄ«ties kā kaut kas pabeigts... neatkarÄ«gi no tā, vai jÅ«su kods darbojas ātri vai lēni. Es turpināju strādāt pie sadalÄ«tāja, lai tas veiktu labākas atlases. ViņŔ kļuva arvien lēnāks, bet viņŔ sniedza arvien labāku sniegumu gadÄ«jumos, kad neviens cits netika galā. Es varētu ienirt reÄ£istru sadalÄ«tājā, aprakt tur mēnesi darba, un pēkŔņi viss kods sāktu izpildÄ«t par 5% ātrāk. Tas notika ik pa laikam un reÄ£istra sadalÄ«tājs kļuva par mākslas darbu - visiem tas patika vai ienÄ«da, un akadēmijas cilvēki uzdeva jautājumus par tēmu "kāpēc viss tiek darÄ«ts tā", kāpēc ne lÄ«niju skenÄ“Å”ana, un kāda starpÄ«ba. Atbilde joprojām ir tā pati: sadalÄ«tājs, kas balstÄ«ts uz grafiku krāsoÅ”anu un ļoti rÅ«pÄ«gu darbu ar bufera kodu, ir lÄ«dzvērtÄ«gs uzvaras ierocim, vislabākajai kombinācijai, kuru neviens nevar uzvarēt. Un tā ir diezgan nenozÄ«mÄ«ga lieta. Viss pārējais, ko tur dara sastādÄ«tājs, ir diezgan labi izpētÄ«tas lietas, kaut arÄ« tās ir novestas lÄ«dz mākslas lÄ«menim. Es vienmēr darÄ«ju lietas, kurām vajadzēja pārvērst kompilatoru par mākslas darbu. Bet nekas no tā nebija nekas ārkārtējs ā€“ izņemot reÄ£istru sadalÄ«tāju. Triks ir bÅ«t uzmanÄ«giem nocirst zem slodzes, un, ja tas notiek (ja interesē, varu paskaidrot sÄ«kāk), tas nozÄ«mē, ka jÅ«s varat iesaistÄ«ties agresÄ«vāk, neriskējot pārkrist uzstāŔanās grafikā. Tajos laikos bija bariņŔ pilna mēroga kompilatoru, kas bija apkarināti ar baubām un svilpieniem, kuriem bija reÄ£istru sadalÄ«tāji, bet neviens cits to nevarēja izdarÄ«t.

Problēma ir tāda, ka, ja pievienojat metodes, kas ir pakļautas ieklāŔanai, palielināŔanai un ieklāŔanas zonas palielināŔanai, izmantoto vērtÄ«bu kopa uzreiz pārspēj reÄ£istru skaitu, un jums tās ir jāsamazina. Kritiskais lÄ«menis parasti iestājas, kad sadalÄ«tājs padodas, un viens labs kandidāts noplÅ«dei ir cita vērts, jÅ«s pārdosit dažas vispār mežonÄ«gas lietas. IekļauÅ”anas vērtÄ«ba Å”eit ir tāda, ka jÅ«s zaudējat daļu no pieskaitāmajām izmaksām, pieskaitāmās izmaksas par zvanÄ«Å”anu un saglabāŔanu, jÅ«s varat redzēt vērtÄ«bas iekÅ”pusē un varat tās vēl vairāk optimizēt. IeklāŔanas izmaksas ir tādas, ka veidojas liels skaits dzÄ«vu vērtÄ«bu, un, ja jÅ«su reÄ£istra sadalÄ«tājs izdeg vairāk nekā nepiecieÅ”ams, jÅ«s uzreiz zaudējat. Tāpēc lielākajai daļai sadalÄ«tāju ir problēma: kad inlining Ŕķērso noteiktu lÄ«niju, viss pasaulē sāk cirst un produktivitāte var tikt noskalota tualetē. Tie, kas ievieÅ” kompilatoru, pievieno dažas heiristikas: piemēram, lai pārtrauktu iekļauÅ”anu, sākot ar kādu pietiekami lielu izmēru, jo pieŔķīrumi visu sabojās. Tādā veidā tiek izveidots locÄ«jums veiktspējas grafikā - jÅ«s inline, inline, sniegums lēnām aug - un tad bum! ā€“ tas nokrÄ«t kā ātrs domkrats, jo jÅ«s pārāk daudz oderējāt. Šādi viss darbojās pirms Java parādÄ«Å”anās. Javai ir nepiecieÅ”ams daudz vairāk inlining, tāpēc man bija jāpadara savs sadalÄ«tājs daudz agresÄ«vāks, lai tas izlÄ«dzinātu, nevis avarē, un, ja jÅ«s ievietojat pārāk daudz, tas sāk izliet, bet tad joprojām pienāk brÄ«dis "ne vairāk spilling". Å is ir interesants novērojums, un tas man vienkārÅ”i radās no nekurienes, nav acÄ«mredzams, bet tas labi atmaksājās. Es izmantoju agresÄ«vu ieklāŔanu, un tas mani aizveda uz vietām, kur Java un C veiktspēja darbojas blakus. Tie ir ļoti tuvu ā€” es varu uzrakstÄ«t Java kodu, kas ir ievērojami ātrāks nekā C kods un tamlÄ«dzÄ«gas lietas, bet vidēji kopumā tās ir aptuveni salÄ«dzināmas. Es domāju, ka daļa no Ŕī nopelna ir reÄ£istru sadalÄ«tājs, kas ļauj man iekļauties pēc iespējas stulbāk. Es vienkārÅ”i iekļauju visu, ko redzu. Å eit jautājums ir par to, vai sadalÄ«tājs darbojas labi, vai rezultāts ir saprātÄ«gi strādājoÅ”s kods. Tas bija liels izaicinājums: to visu saprast un likt tam darboties.

Mazliet par reģistru pieŔķirŔanu un daudzkodolu

Vladimir: Tādas problēmas kā reÄ£istru pieŔķirÅ”ana Ŕķiet kaut kāda mūžīga, nebeidzama tēma. Interesanti, vai kādreiz ir bijusi ideja, kas Ŕķita daudzsoloÅ”a un pēc tam izgāzās praksē?

Klints: Noteikti! ReÄ£istra pieŔķirÅ”ana ir apgabals, kurā mēģināt atrast heiristikas metodes, lai atrisinātu NP pilnÄ«gu problēmu. Un jÅ«s nekad nevarat sasniegt ideālu risinājumu, vai ne? Tas ir vienkārÅ”i neiespējami. Paskaties, Ahead of Time kompilācija ā€“ arÄ« tā darbojas slikti. Saruna Å”eit ir par dažiem vidējiem gadÄ«jumiem. Par tipisku veiktspēju, lai jÅ«s varētu iet un izmērÄ«t kaut ko, kas, jÅ«suprāt, ir labs tipisks sniegums - galu galā jÅ«s strādājat, lai to uzlabotu! ReÄ£istru pieŔķirÅ”ana ir tēma par veiktspēju. Kad jums ir pirmais prototips, tas darbojas un nokrāso nepiecieÅ”amo, sākas izpildes darbs. Ir jāiemācās labi izmērÄ«t. Kāpēc tas ir svarÄ«gi? Ja jums ir skaidri dati, varat aplÅ«kot dažādas jomas un redzēt: jā, Å”eit tas palÄ«dzēja, bet tur viss sabojājās! Rodas dažas labas idejas, jÅ«s pievienojat jaunu heiristiku un pēkŔņi viss sāk darboties vidēji nedaudz labāk. Vai arÄ« nesākas. Man bija virkne gadÄ«jumu, kad mēs cÄ«nÄ«jāmies par piecu procentu veiktspēju, kas atŔķīra mÅ«su attÄ«stÄ«bu no iepriekŔējā sadalÄ«tāja. Un katru reizi tas izskatās Ŕādi: kaut kur tu uzvari, kaut kur zaudē. Ja jums ir labi veiktspējas analÄ«zes rÄ«ki, varat atrast zaudētās idejas un saprast, kāpēc tās neizdodas. VarbÅ«t ir vērts atstāt visu, kā tas ir, vai varbÅ«t nopietnāk pieiet pie precizÄ“Å”anas, vai iziet un kaut ko citu salabot. Tā ir vesela virkne lietu! Es izveidoju Å”o forÅ”o uzlauÅ”anu, bet man vajag arÄ« Å”o, un Å”o, un Å”o - un to kopējā kombinācija sniedz dažus uzlabojumus. Un vientuļnieki var neizdoties. Tāds ir veiktspējas darbs pie NP pilnÄ«gām problēmām.

Vladimir: Rodas sajÅ«ta, ka tādas lietas kā krāsoÅ”ana alokatoros ir problēma, kas jau ir atrisināta. Nu, tas ir izlemts jÅ«su vietā, spriežot pēc jÅ«su teiktā, vai tad tas ir tā vērts...

Klints: Tas nav atrisināts kā tāds. Jums tas ir jāpārvērÅ” par ā€œatrisinātuā€. Ir sarežģītas problēmas, un tās ir jārisina. Kad tas ir izdarÄ«ts, ir pienācis laiks strādāt pie produktivitātes. Jums ir attiecÄ«gi jāpieiet Å”im darbam - veiciet etalonus, apkopojiet metriku, izskaidrojiet situācijas, kad, atgriežoties pie iepriekŔējās versijas, jÅ«su vecais uzlauzums atkal sāka darboties (vai otrādi, apstājās). Un nepadodies, kamēr kaut ko nesasniegsi. Kā jau teicu, ja ir forÅ”as idejas, kas neizdevās, bet ideju reÄ£istru sadales jomā tas ir aptuveni bezgalÄ«gi. Varat, piemēram, lasÄ«t zinātniskas publikācijas. Lai gan tagad Ŕī joma ir sākusi kustēties daudz lēnāk un kļuvusi skaidrāka nekā jaunÄ«bā. Taču Å”ajā jomā strādā neskaitāmi daudz cilvēku un visas viņu idejas ir izmēģināŔanas vērtas, tās visas gaida spārnos. Un jÅ«s nevarat pateikt, cik tie ir labi, ja vien jÅ«s tos neizmēģināsit. Cik labi tās integrējas ar visu pārējo jÅ«su sadalÄ«tājā, jo alokators dara daudzas lietas, un dažas idejas jÅ«su konkrētajā sadalÄ«tājā nedarbosies, bet citā sadalÄ«tājā tās viegli. Galvenais veids, kā laimēt sadalÄ«tāju, ir izvilkt lēnās lietas ārpus galvenā ceļa un piespiest to sadalÄ«t pa lēno ceļu robežām. Tātad, ja vēlaties palaist GC, izvēlieties lēno ceļu, deoptimizējiet, izņemiet izņēmumu, visu Å”o lietu - jÅ«s zināt, ka Ŕīs lietas ir salÄ«dzinoÅ”i reti. Un tie ir patieŔām reti, es pārbaudÄ«ju. JÅ«s veicat papildu darbu, un tas atceļ daudzus ierobežojumus Å”iem lēnajiem ceļiem, taču tas nav Ä«sti svarÄ«gi, jo tie ir lēni un reti brauc. Piemēram, nulles rādÄ«tājs - tas nekad nenotiek, vai ne? Jums ir jābÅ«t vairākiem ceļiem dažādām lietām, taču tiem nevajadzētu traucēt galveno. 

Vladimir: Ko jūs domājat par daudzkodolu, ja ir tūkstoŔiem kodolu vienlaikus? Vai tā ir noderīga lieta?

Klints: GPU panākumi liecina, ka tas ir diezgan noderīgs!

Vladimir: Tie ir diezgan specializēti. Kā ar vispārējas nozīmes procesoriem?

Klints: Tāds bija Azula biznesa modelis. Atbilde radās laikmetā, kad cilvēkiem ļoti patika paredzama veiktspēja. Toreiz bija grÅ«ti rakstÄ«t paralēlo kodu. H2O kodÄ“Å”anas modelis ir ļoti mērogojams, taču tas nav vispārēja mērÄ·a modelis. VarbÅ«t nedaudz vispārÄ«gāks nekā tad, ja tiek izmantots GPU. Vai mēs runājam par Ŕādas lietas izstrādes sarežģītÄ«bu vai tās izmantoÅ”anas sarežģītÄ«bu? Piemēram, Azuls man iemācÄ«ja interesantu stundu, kas bija diezgan acÄ«mredzama: mazas keÅ”atmiņas ir normālas. 

Lielākais izaicinājums dzīvē

Vladimir: Kā ir ar netehniskiem izaicinājumiem?

Klints: Lielākais izaicinājums bija nebÅ«t... laipnam un jaukam pret cilvēkiem. Un rezultātā es pastāvÄ«gi nokļuvu ārkārtÄ«gi konfliktsituācijās. Tās, kurās es zināju, ka lietas notiek nepareizi, bet nezināju, kā risināt Ŕīs problēmas, un nevarēju ar tām tikt galā. Tādā veidā radās daudzas ilgtermiņa problēmas, kas ilga gadu desmitiem. Fakts, ka Java ir C1 un C2 kompilatori, ir tieÅ”as sekas tam. Fakts, ka desmit gadus pēc kārtas Java valodā nebija daudzlÄ«meņu kompilācijas, arÄ« ir tieÅ”as sekas. Ir skaidrs, ka mums bija vajadzÄ«ga Ŕāda sistēma, bet nav skaidrs, kāpēc tā nepastāvēja. Man bija problēmas ar vienu inženieri... vai inženieru grupu. Kādreiz, kad sāku strādāt Sun, es biju... Labi, ne tikai tad, man vispār vienmēr par visu ir savs viedoklis. Un es domāju, ka tā ir taisnÄ«ba, ka jÅ«s varat vienkārÅ”i pieņemt Å”o savu patiesÄ«bu un izstāstÄ«t to. Jo Ä«paÅ”i tāpēc, ka lielāko daļu laika man bija Å”okējoÅ”i taisnÄ«ba. Un, ja jums nepatÄ«k Ŕī pieeja... it Ä«paÅ”i, ja jÅ«s acÄ«mredzami maldāties un darāt muļķības... Kopumā reti kurÅ” varētu paciest Å”o komunikācijas veidu. Lai gan daži varētu, piemēram, es. Es visu savu dzÄ«vi esmu veidojis uz meritokrātiskiem principiem. Ja tu man parādÄ«si kaut ko nepareizi, es uzreiz pagriezos un teikÅ”u: tu teici muļķības. Tajā paŔā laikā es, protams, atvainojos un viss, es atzÄ«mÄ“Å”u nopelnus, ja tādi bÅ«s, un rÄ«koÅ”os citas pareizas darbÄ«bas. No otras puses, man ir Å”okējoÅ”i taisnÄ«ba par Å”okējoÅ”i lielu procentuālo daļu no kopējā laika. Un tas ne pārāk labi darbojas attiecÄ«bās ar cilvēkiem. Es necenÅ”os bÅ«t jauks, bet uzdodu jautājumu atklāti. "Tas nekad nedarbosies, jo viens, divi un trÄ«s." Un viņi teica: "Ak!" Bija arÄ« citas sekas, kuras, iespējams, bija labāk ignorēt: piemēram, tās, kas noveda pie ŔķirÅ”anās no sievas un desmit gadus ilgas depresijas pēc tam.

Izaicinājums ir cīņa ar cilvēkiem, ar viņu uztveri par to, ko jÅ«s varat vai nevarat, kas ir svarÄ«gi un kas nav. Bija daudz problēmu saistÄ«bā ar kodÄ“Å”anas stilu. Es joprojām rakstu daudz koda, un tajos laikos man pat nācās piebremzēt, jo es veicu pārāk daudz paralēlu uzdevumu un darÄ«ju tos slikti, nevis koncentrējos uz vienu. Atskatoties atpakaļ, es uzrakstÄ«ju pusi koda Java JIT komandai, komandai C2. Nākamais ātrākais kodētājs rakstÄ«ja uz pusi lēnāk, nākamais uz pusi lēnāk, un tas bija eksponenciāls kritums. SeptÄ«tais cilvēks Å”ajā rindā bija ļoti, ļoti lēns ā€“ tā notiek vienmēr! Es pieskāros daudz koda. Es paskatÄ«jos, kurÅ” ko ir rakstÄ«jis, bez izņēmuma skatÄ«jos uz viņu kodu, pārskatÄ«ju katru no tiem un joprojām turpināju rakstÄ«t vairāk pats nekā jebkurÅ” no viņiem. Å Ä« pieeja nedarbojas ļoti labi ar cilvēkiem. Dažiem cilvēkiem tas nepatÄ«k. Un, kad viņi netiek galā, sākas visādas sÅ«dzÄ«bas. Piemēram, man reiz teica pārtraukt kodÄ“Å”anu, jo es rakstÄ«ju pārāk daudz koda un tas apdraud komandu, un man tas viss izklausÄ«jās kā joks: vecÄ«t, ja pārējā komanda pazÅ«d un es turpinu rakstÄ«t kodu, tu ZaudÄ“Å”u tikai pusi komandas. No otras puses, ja es turpinu rakstÄ«t kodu un jÅ«s zaudējat pusi komandas, tas izklausās pēc ļoti sliktas pārvaldÄ«bas. Es nekad Ä«sti par to nedomāju, nekad par to nerunāju, bet tas joprojām bija kaut kur manā galvā. Manā prātā griezās doma: "Vai jÅ«s visi mani jokojat?" Tātad lielākā problēma bija es un manas attiecÄ«bas ar cilvēkiem. Tagad es sevi saprotu daudz labāk, ilgu laiku biju programmētāju komandas vadÄ«tājs, un tagad tieÅ”i saku cilvēkiem: ziniet, es esmu tāds, kāds esmu, un jums ar mani bÅ«s jātiek galā - vai ir labi, ja es stāvÄ“Å”u. Å”eit? Un, kad viņi sāka ar to nodarboties, viss izdevās. PatiesÄ«bā es neesmu ne slikts, ne labs, man nav nekādu sliktu nodomu vai savtÄ«gu centienu, tā ir tikai mana bÅ«tÄ«ba, un man ar to kaut kā jāsadzÄ«vo.

Andrejs: Pavisam nesen visi sāka runāt par intravertu paÅ”apziņu un mÄ«kstajām prasmēm kopumā. Ko jÅ«s varat teikt par Å”o?

Klints: Jā, tā bija atziņa un mācÄ«ba, ko es guvu ŔķirÅ”anās laikā no savas sievas. Tas, ko es iemācÄ«jos no ŔķirÅ”anās, bija izpratne par sevi. Tā es sāku saprast citus cilvēkus. Izprotiet, kā Ŕī mijiedarbÄ«ba darbojas. Tas noveda pie atklājumiem viens pēc otra. Bija apziņa, kas es esmu un ko pārstāvu. Ko es daru: vai nu esmu aizņemts ar uzdevumu, vai arÄ« izvairos no konfliktiem, vai kaut kas cits ā€“ un Å”is paÅ”apziņas lÄ«menis patieŔām palÄ«dz noturēt sevi savā kontrolē. Pēc tam viss iet daudz vieglāk. Viena lieta, ko es atklāju ne tikai sevÄ«, bet arÄ« citos programmētājos, ir nespēja verbalizēt domas, kad esat emocionālā stresa stāvoklÄ«. Piemēram, jÅ«s sēžat un kodējat plÅ«smas stāvoklÄ«, un tad viņi pieskrien pie jums un sāk histēriski kliegt, ka kaut kas ir salÅ«zis, un tagad pret jums tiks veikti ārkārtēji pasākumi. Un jÅ«s nevarat pateikt ne vārda, jo esat emocionālā stresa stāvoklÄ«. IegÅ«tās zināŔanas ļauj sagatavoties Å”im brÄ«dim, izdzÄ«vot to un pāriet uz atkāpÅ”anās plānu, pēc kura var kaut ko darÄ«t. Tātad, jā, kad jÅ«s sākat saprast, kā tas viss darbojas, tas ir milzÄ«gs notikums, kas maina dzÄ«vi. 
Es pats nevarēju atrast Ä«stos vārdus, bet atcerējos darbÄ«bu secÄ«bu. Lieta ir tāda, ka Ŕī reakcija ir tikpat fiziska, kā verbāla, un jums ir nepiecieÅ”ama telpa. Tāda telpa dzena izpratnē. Tas ir tieÅ”i tas, kas ir jāpaskaidro, un tad uzreiz paiet malā ā€“ tÄ«ri fiziski atkāpieties. Kad es klusēju mutiski, es varu emocionāli apstrādāt situāciju. Kad adrenalÄ«ns sasniedz jÅ«su smadzenes, pārslēdz jÅ«s cīņas vai lidojuma režīmā, jÅ«s vairs nevarat neko pateikt, nē - tagad jÅ«s esat idiots, pātagu inženieris, kas nespēj pienācÄ«gi reaģēt vai pat apturēt uzbrukumu, un uzbrucējs ir brÄ«vs. uzbrukt atkal un atkal. Vispirms atkal jākļūst par sevi, jāatgÅ«st kontrole, jāiziet no režīma ā€œcÄ«nies vai bēgtā€.

Un Å”im nolÅ«kam mums ir nepiecieÅ”ama verbālā telpa. Tikai brÄ«va vieta. Ja vispār kaut ko saki, tad vari pateikt tieÅ”i tā un tad ej un tieŔām atrodi sev ā€œvietuā€: dodies pastaigā pa parku, ieslēdzies duŔā - tam nav nozÄ«mes. Galvenais ir uz laiku atvienoties no Ŕīs situācijas. TiklÄ«dz jÅ«s izslēdzaties vismaz uz dažām sekundēm, kontrole atgriežas, jÅ«s sākat domāt prātÄ«gi. "Labi, es neesmu nekāds idiots, es nedaru stulbas, es esmu diezgan noderÄ«gs cilvēks." Kad esat spējuÅ”i sevi pārliecināt, ir pienācis laiks pāriet uz nākamo posmu: izprast notikuÅ”o. Jums uzbruka, uzbrukums nāca no vietas, kur jÅ«s to negaidÄ«jāt, tā bija negodÄ«ga, zemiska slazds. Tas ir slikti. Nākamais solis ir saprast, kāpēc uzbrucējam tas bija vajadzÄ«gs. TieŔām, kāpēc? VarbÅ«t tāpēc, ka viņŔ pats ir saÅ”utis? Kāpēc viņŔ ir dusmÄ«gs? Piemēram, tāpēc, ka viņŔ pats ir ieskrÅ«vējis un nevar uzņemties atbildÄ«bu? Tas ir veids, kā rÅ«pÄ«gi rÄ«koties ar visu situāciju. Bet tas prasa manevra telpu, verbālo telpu. Pats pirmais solis ir pārtraukt verbālo kontaktu. Izvairieties no diskusijām ar vārdiem. Atceliet to, dodieties prom, cik ātri vien iespējams. Ja tā ir telefonsaruna, vienkārÅ”i nolieciet klausuli ā€“ tā ir prasme, ko es apguvu, sazinoties ar savu bijuÅ”o sievu. Ja saruna nevedās, vienkārÅ”i sakiet "ardievu" un nolieciet klausuli. No otras telefona puses: "bla bla blah", jÅ«s atbildat: "jā, čau!" un noliec klausuli. JÅ«s vienkārÅ”i pabeidzat sarunu. Pēc piecām minÅ«tēm, kad tevÄ« atgriežas spēja domāt saprātÄ«gi, tu esi nedaudz atdzisis, kļūst iespējams pārdomāt visu, notikuÅ”o un tālāko. Un sāciet formulēt pārdomātu atbildi, nevis vienkārÅ”i reaģējot emociju dēļ. Man paÅ”apziņas izrāviens bija tieÅ”i tas, ka emocionāla stresa gadÄ«jumā nevaru runāt. IzkāpÅ”ana no Ŕī stāvokļa, domāŔana un plānoÅ”ana, kā reaģēt un kompensēt problēmas - tie ir pareizie soļi gadÄ«jumā, ja nevarat runāt. VienkārŔākais veids ir aizbēgt no situācijas, kurā izpaužas emocionāls stress, un vienkārÅ”i pārtraukt piedalÄ«ties Å”ajā stresā. Pēc tam jÅ«s kļūstat spējÄ«gs domāt, kad jÅ«s varat domāt, jÅ«s kļūstat spējÄ«gs runāt utt.

Starp citu, tiesā pretējās puses advokāts mēģina jums to izdarÄ«t - tagad ir skaidrs, kāpēc. Jo viņam ir spēja tevi nomākt lÄ«dz tādam stāvoklim, ka tu pat nevari izrunāt, piemēram, savu vārdu. Ä»oti reālā nozÄ«mē jÅ«s nevarēsit runāt. Ja tas notiek ar jums un ja zināt, ka nonāksit vietā, kur plosās verbālās cīņas, tādā vietā kā tiesa, varat ierasties ar savu advokātu. Advokāts iestāsies par jums un apturēs verbālo uzbrukumu, un darÄ«s to pilnÄ«gi likumÄ«gā veidā, un zaudētā Zen telpa atgriezÄ«sies pie jums. Piemēram, man pāris reizes nācās zvanÄ«t Ä£imenei, tiesnesis par to bija diezgan draudzÄ«gs, bet pretinieku advokāts uz mani kliedza un kliedza, es pat nevarēju saņemties ne vārda. Šādos gadÄ«jumos man vislabāk der mediatora izmantoÅ”ana. Starpnieks aptur visu Å”o spiedienu, kas nepārtrauktā straumē plÅ«st uz jums, jÅ«s atrodat nepiecieÅ”amo Zen telpu, un lÄ«dz ar to atgriežas spēja runāt. Å Ä« ir vesela zināŔanu joma, kurā ir daudz ko pētÄ«t, daudz ko atklāt sevÄ«, un tas viss pārvērÅ”as augsta lÄ«meņa stratēģiskos lēmumos, kas dažādiem cilvēkiem ir atŔķirÄ«gi. Dažiem cilvēkiem nav iepriekÅ” aprakstÄ«to problēmu; parasti cilvēkiem, kas ir profesionāli pārdevēji, to nav. Visiem Å”iem cilvēkiem, kuri pelna ar vārdiem ā€“ slaveni dziedātāji, dzejnieki, reliÄ£iskie vadÄ«tāji un politiÄ·i, viņiem vienmēr ir ko teikt. Viņiem tādu problēmu nav, bet man ir.

Andrejs: Tas bija... negaidÄ«ti. Lieliski, mēs jau esam daudz runājuÅ”i, un ir pienācis laiks beigt Å”o interviju. Mēs noteikti tiksimies konferencē un varēsim turpināt Å”o dialogu. Tiekamies Hydra!

Sarunu ar Klifu varat turpināt konferencē Hydra 2019, kas notiks 11. gada 12.-2019.jÅ«lijā Sanktpēterburgā. ViņŔ nāks ar ziņojumu "Azul aparatÅ«ras transakciju atmiņas pieredze". Biļetes var iegādāties oficiālajā tÄ«mekļa vietnē.

Avots: www.habr.com

Pievieno komentāru