Java-da JIT kompilyasiyasının atası Cliff Click ilə əla müsahibə

Java-da JIT kompilyasiyasının atası Cliff Click ilə əla müsahibəCliff Click — Cratus şirkətinin texniki direktoru (proseslərin təkmilləşdirilməsi üçün IoT sensorları), bir neçə uğurlu çıxışı olan bir neçə startapın (o cümlədən Rocket Realtime School, Neurensic və H2O.ai) təsisçisi və həmtəsisçisi. Cliff ilk tərtibçisini 15 yaşında (TRS Z-80 üçün Paskal) yazdı! O, Java-da (The Sea of ​​Nodes IR) C2 üzərindəki işi ilə məşhurdur. Bu kompilyator dünyaya JIT-nin yüksək keyfiyyətli kod istehsal edə biləcəyini göstərdi ki, bu da Java-nın əsas müasir proqram platformalarından biri kimi yaranmasının amillərindən biri idi. Sonra Cliff Azul Systems-ə 864 millisaniyə ərzində 500 giqabaytlıq yığında GC pauzalarını dəstəkləyən təmiz Java proqramı ilə 10 nüvəli meynfreym qurmağa kömək etdi. Ümumiyyətlə, Cliff JVM-in bütün aspektləri üzərində işləməyi bacardı.

 
Bu habrapost Clifflə əla müsahibədir. Aşağıdakı mövzularda danışacağıq:

  • Aşağı səviyyəli optimallaşdırmalara keçid
  • Böyük bir refaktorinqi necə etmək olar
  • Xərc modeli
  • Aşağı səviyyəli optimallaşdırma təlimi
  • Performansın yaxşılaşdırılmasının praktiki nümunələri
  • Niyə öz proqramlaşdırma dilinizi yaradın
  • Performans Mühəndisi Karyera
  • Texniki Çağırışlar
  • Qeydiyyatın ayrılması və çox nüvəli haqqında bir az
  • Həyatda ən böyük sınaq

Müsahibəni aparır:

  • Andrey Satarin Amazon Veb Xidmətlərindən. Karyerasında o, tamamilə fərqli layihələrdə işləməyi bacarıb: o, Yandex-də paylanmış NewSQL verilənlər bazasını, Kaspersky Lab-da bulud aşkarlama sistemini, Mail.ru-da multiplayer oyununu və Deutsche Bank-da valyuta qiymətlərinin hesablanması xidmətini sınaqdan keçirib. Geniş miqyaslı backend və paylanmış sistemləri sınamaqda maraqlıdır.
  • Vladimir Sitnikov Netcracker-dən. Telekommunikasiya operatorları tərəfindən şəbəkə və şəbəkə avadanlığının idarəetmə proseslərinin avtomatlaşdırılması üçün istifadə olunan proqram təminatı olan NetCracker ƏS-nin performansı və miqyası üzrə on illik iş. Java və Oracle Database performans problemləri ilə maraqlanır. Rəsmi PostgreSQL JDBC sürücüsündə ondan çox performans təkmilləşdirməsinin müəllifidir.

Aşağı səviyyəli optimallaşdırmalara keçid

Andrew: Siz JIT kompilyasiyası, Java və ümumilikdə performans işi dünyasında böyük bir adsınız, elə deyilmi? 

Uçurum: Belədir!

Andrew: Performans işi ilə bağlı bəzi ümumi suallarla başlayaq. CPU səviyyəsində işləmək kimi yüksək səviyyəli və aşağı səviyyəli optimallaşdırmalar arasında seçim haqqında nə düşünürsünüz?

Uçurum: Bəli, burada hər şey sadədir. Ən sürətli kod heç vaxt işləməyən koddur. Ona görə də həmişə yüksək səviyyədən başlamaq, alqoritmlər üzərində işləmək lazımdır. Bəzi kifayət qədər böyük sabitlər müdaxilə etməsə, daha yaxşı O notasiyası daha pis O notasiyasını döyəcək. Aşağı səviyyəli işlər ən sonda gedir. Tipik olaraq, yığınınızın qalan hissəsini kifayət qədər optimallaşdırmısınızsa və hələ də maraqlı şeylər qalıbsa, bu, aşağı səviyyədir. Bəs yüksək səviyyədən necə başlamaq lazımdır? Siz haradan bilirsiniz ki, kifayət qədər yüksək səviyyədə iş görülüb? Yaxşı... olmaz. Hazır reseptlər yoxdur. Problemi başa düşməli, nə edəcəyinizə qərar verməlisiniz (gələcəkdə lazımsız addımlar atmamaq üçün) və sonra faydalı bir şey deyə biləcək profilçini aça bilərsiniz. Bir nöqtədə, özünüz dərk edirsiniz ki, lazımsız şeylərdən qurtulmusunuz və aşağı səviyyəli incə tənzimləmə etmək vaxtıdır. Bu, şübhəsiz ki, xüsusi bir sənət növüdür. Bir çox insan lazımsız işlərlə məşğuldur, lakin o qədər sürətlə hərəkət edir ki, məhsuldarlıqdan narahat olmağa vaxtları qalmır. Ancaq bu, sual açıq şəkildə ortaya çıxana qədərdir. Adətən 99% zaman heç kimin əhəmiyyət vermədiyi kritik yolda vacib bir şey gələnə qədər mənim nə etdiyimlə maraqlanmır. Və burada hamı sizi “niyə əvvəldən mükəmməl işləmədi” deyə yalvarmağa başlayır. Ümumiyyətlə, performansda həmişə yaxşılaşdırılacaq bir şey var. Ancaq vaxtın 99% -ində heç bir lider yoxdur! Siz sadəcə nəyisə işə salmağa çalışırsınız və bu prosesdə nəyin vacib olduğunu anlayırsınız. Bu parçanın mükəmməl olması lazım olduğunu heç vaxt əvvəlcədən bilə bilməzsiniz, buna görə də əslində hər şeydə mükəmməl olmalısınız. Ancaq bu mümkün deyil və siz bunu etmirsiniz. Həmişə düzəltmək üçün çox şey var - və bu tamamilə normaldır.

Böyük bir refaktorinqi necə etmək olar

Andrew: Bir tamaşa üzərində necə işləyirsiniz? Bu, kəsişən problemdir. Məsələn, bir çox mövcud funksionallığın kəsişməsindən yaranan problemlər üzərində işləməli olmusunuzmu?

Uçurum: Mən bundan qaçmağa çalışıram. Performansın bir problem olacağını bilsəm, kodlaşdırmaya başlamazdan əvvəl bu barədə düşünürəm, xüsusən də məlumat strukturları ilə. Ancaq çox vaxt bütün bunları çox sonra kəşf edirsən. Və sonra həddindən artıq tədbirlərə getməli və "yenidən yaz və fəth et" dediyim şeyi etməlisən: kifayət qədər böyük bir parça tutmalısan. Performans problemlərinə və ya başqa bir şeyə görə kodun bəziləri hələ də yenidən yazılmalıdır. Kodun yenidən yazılmasının səbəbi nə olursa olsun, kiçik bir parçadan daha böyük bir parçanı yenidən yazmaq demək olar ki, həmişə daha yaxşıdır. Bu anda hamı qorxudan titrəməyə başlayır: “Aman Allahım, bu qədər kodlara toxuna bilməzsən!” Ancaq əslində bu yanaşma demək olar ki, həmişə daha yaxşı işləyir. Dərhal böyük bir problemi öz üzərinə götürməli, onun ətrafında böyük bir dairə çəkməli və deməlisən: Mən dairənin içindəki hər şeyi yenidən yazacağam. Haşiyə dəyişdirilməsi lazım olan içindəki məzmundan çox kiçikdir. Və əgər sərhədlərin belə müəyyənləşdirilməsi içəridəki işi mükəmməl görməyə imkan verirsə, əlləriniz boşdur, istədiyinizi edin. Problemi başa düşdükdən sonra yenidən yazmaq prosesi daha asan olacaq, ona görə də böyük bir dişlənin!
Eyni zamanda, böyük bir yenidən yazdığınız zaman və performansın bir problem olacağını başa düşsəniz, dərhal bu barədə narahat olmağa başlaya bilərsiniz. Bu, adətən “məlumatları kopyalamayın, məlumatları mümkün qədər sadə şəkildə idarə edin, kiçik edin” kimi sadə şeylərə çevrilir. Böyük yenidən yazılarda performansı yaxşılaşdırmaq üçün standart yollar var. Və onlar demək olar ki, həmişə məlumatların ətrafında fırlanırlar.

Xərc modeli

Andrew: Podkastların birində məhsuldarlıq kontekstində xərc modellərindən danışdınız. Bununla nə demək istədiyinizi izah edə bilərsinizmi?

Uçurum: Əlbəttə. Mən prosessor performansının son dərəcə vacib olduğu bir dövrdə doğulmuşam. Və bu dövr yenidən qayıdır - taleyi ironiyasız deyil. Mən səkkiz bitlik maşınların dövründə yaşamağa başladım; ilk kompüterim 256 baytla işləyirdi. Məhz bayt. Hər şey çox kiçik idi. Təlimatları hesablamaq lazım idi və biz proqramlaşdırma dili yığınını yüksəltməyə başlayanda dillər getdikcə daha çox şey aldı. Assembler var idi, sonra Basic, sonra C və C registrlərin ayrılması və təlimat seçimi kimi bir çox detallara diqqət yetirdi. Amma orada hər şey tam aydın idi və mən dəyişən instansiyasına göstərici etsəydim, onda mən yüklənərdim və bu təlimatın qiyməti məlumdur. Aparat müəyyən sayda maşın dövrü istehsal edir, buna görə də müxtəlif şeylərin icra sürəti sadəcə işləyəcəyiniz bütün təlimatları əlavə etməklə hesablana bilər. Hər bir müqayisə/sınaq/filial/zəng/yükləmə/mağaza əlavə oluna və dedi: bu sizin üçün icra vaxtıdır. Performansın yaxşılaşdırılması üzərində işləyərkən, mütləq hansı nömrələrin kiçik isti dövrlərə uyğun olduğuna diqqət yetirəcəksiniz. 
Ancaq Java, Python və buna bənzər şeylərə keçən kimi aşağı səviyyəli aparatdan çox tez uzaqlaşırsınız. Java-da alıcıya zəng etməyin qiyməti nə qədərdir? HotSpot-da JIT düzgündürsə sətirli, yüklənəcək, lakin bunu etməyibsə, bu, funksiya çağırışı olacaq. Zəng isti dövrədə olduğundan, bu dövrədə bütün digər optimallaşdırmaları ləğv edəcək. Buna görə də real xərclər xeyli yüksək olacaq. Və siz dərhal bir kod parçasına baxmaq qabiliyyətini itirirsiniz və onu prosessorun saat sürəti, yaddaş və istifadə olunan yaddaş baxımından yerinə yetirməli olduğumuzu başa düşürsünüz. Bütün bunlar yalnız tamaşaya həqiqətən daxil olduqda maraqlı olur.
İndi özümüzü prosessor sürətlərinin on il ərzində çətin ki artdığı bir vəziyyətdə tapırıq. Köhnə günlər geri döndü! Siz artıq yaxşı tək yivli performansa arxalana bilməzsiniz. Ancaq birdən paralel hesablamaya girsəniz, bu, inanılmaz dərəcədə çətindir, hamı sizə James Bond kimi baxır. Burada on qat sürətlənmə adətən kiminsə nəyisə pozduğu yerlərdə baş verir. Paralellik çox iş tələb edir. Bu XNUMXx sürəti əldə etmək üçün xərc modelini başa düşməlisiniz. Nəyə və neçəyə başa gəlir? Və bunu etmək üçün dilin əsas aparata necə uyğun olduğunu başa düşməlisiniz.
Martin Thompson bloqu üçün əla söz seçdi Mexanik simpatiya! Aparatın nə edəcəyini, bunu necə dəqiq edəcəyini və ilk növbədə nə üçün etdiyini başa düşməlisiniz. Bundan istifadə edərək, təlimatları saymağa və icra vaxtının hara getdiyini anlamağa başlamaq kifayət qədər asandır. Müvafiq təliminiz yoxdursa, sadəcə qaranlıq otaqda qara pişik axtarırsınız. Mən hər zaman performansı optimallaşdıran insanların nə etdikləri barədə heç bir fikri olmayan insanlar görürəm. Çox əziyyət çəkirlər və çox da irəli getmirlər. Mən eyni kod parçasını götürəndə, bir neçə xırda hack daxil edib beş və ya on qat sürətləndirəndə onlar belə olur: yaxşı, bu ədalətli deyil, biz artıq bilirdik ki, siz daha yaxşısınız. heyrətamiz. Mən nədən danışıram... xərc modeli hansı kod yazmağınızdan və böyük şəkildə orta hesabla nə qədər sürətlə işlədiyindən ibarətdir.

Andrew: Bəs belə bir həcmi beyninizdə necə saxlaya bilərsiniz? Bu daha çox təcrübə ilə əldə edilir, yoxsa? Belə təcrübə haradan gəlir?

Uçurum: Yaxşı, təcrübəmi ən asan yolla almadım. Mən Assambleyada hər bir təlimatı başa düşə biləcəyiniz günlərdə proqramlaşdırdım. Bu axmaq səslənir, amma o vaxtdan bəri Z80 təlimat dəsti həmişə beynimdə, yaddaşımda qalıb. Danışdıqdan bir dəqiqə sonra insanların adlarını xatırlamıram, amma 40 il əvvəl yazılmış kodu xatırlayıram. Gülməli, sindroma oxşayır”axmaq alim.

Aşağı səviyyəli optimallaşdırma təlimi

Andrew: İçəri girməyin daha asan yolu varmı?

Uçurum: Bəli və xeyr. Hamımızın istifadə etdiyi avadanlıq zamanla o qədər də dəyişməyib. Arm smartfonları istisna olmaqla, hamı x86-dan istifadə edir. Bir növ sərt yerləşdirmə ilə məşğul deyilsinizsə, eyni şeyi edirsiniz. Yaxşı, növbəti. Təlimatlar da əsrlər boyu dəyişməyib. Gərək gedib Məclisdə nəsə yazasan. Çox deyil, amma başa düşməyə başlamaq üçün kifayətdir. Sən gülümsəyirsən, amma mən tamamilə ciddi danışıram. Dil və aparat arasındakı yazışmaları başa düşməlisiniz. Bundan sonra gedib bir az yazmaq və bir az oyuncaq dili üçün kiçik oyuncaq kompilyator etmək lazımdır. Oyuncağa bənzəyən o deməkdir ki, onun məqbul vaxt ərzində edilməsi lazımdır. Bu, çox sadə ola bilər, lakin təlimatlar yaratmalıdır. Təlimat yaratmaq aktı hər kəsin yazdığı yüksək səviyyəli kod və aparatda işləyən maşın kodu arasında körpünün xərc modelini başa düşməyə kömək edəcək. Bu yazışma tərtibçinin yazılması zamanı beyinə yanacaq. Hətta ən sadə kompilyator. Bundan sonra Java-ya və onun semantik uçurumunun daha dərin olduğuna və onun üzərində körpülərin qurulmasının daha çətin olduğuna baxmağa başlaya bilərsiniz. Java-da körpüümüzün yaxşı və ya pis olduğunu, nəyin dağılmasına səbəb olacağını və nəyin etməyəcəyini anlamaq daha çətindir. Ancaq koda baxıb başa düşdüyünüz bir növ başlanğıc nöqtəsinə ehtiyacınız var: "bəli, bu alıcı hər dəfə daxil edilməlidir." Və sonra məlum olur ki, bəzən metodun çox böyük olduğu və JIT hər şeyi daxil etməyə başladığı vəziyyət istisna olmaqla, bu baş verir. Belə yerlərin fəaliyyətini dərhal proqnozlaşdırmaq olar. Adətən alıcılar yaxşı işləyir, lakin sonra siz böyük isti döngələrə baxırsınız və orada nə etdiklərini bilməyən bəzi funksiya çağırışlarının üzən olduğunu başa düşürsünüz. Bu, alıcıların geniş istifadəsində problemdir, onların daxil edilməməsinin səbəbi onların alıcı olub-olmamasının aydın olmamasıdır. Əgər super kiçik kod bazanız varsa, onu sadəcə xatırlaya və sonra deyə bilərsiniz: bu alıcıdır, bu isə təyinedicidir. Böyük kod bazasında hər bir funksiya, ümumiyyətlə, heç kimə məlum olmayan öz tarixini yaşayır. Profiler deyir ki, biz hansısa döngədə vaxtın 24%-ni itirmişik və bu döngənin nə etdiyini başa düşmək üçün içəridəki hər bir funksiyaya baxmaq lazımdır. Funksiyanı öyrənmədən bunu anlamaq mümkün deyil və bu, anlama prosesini ciddi şəkildə ləngidir. Buna görə mən alıcı və təyinedicilərdən istifadə etmirəm, yeni səviyyəyə çatmışam!
Qiymət modelini haradan əldə etmək olar? Yaxşı, nəsə oxuya bilərsən, əlbəttə... Amma məncə, ən yaxşı yol hərəkət etməkdir. Kiçik bir kompilyator hazırlamaq, xərc modelini başa düşmək və onu öz başınıza uyğunlaşdırmaq üçün ən yaxşı yol olacaqdır. Mikrodalğalı sobanı proqramlaşdırmaq üçün uyğun olacaq kiçik bir kompilyator yeni başlayanlar üçün bir vəzifədir. Yaxşı, demək istəyirəm ki, əgər siz artıq proqramlaşdırma bacarıqlarınız varsa, bu kifayətdir. Bütün bunlar bir növ cəbri ifadə kimi sahib olduğunuz sətri təhlil etmək, oradan düzgün ardıcıllıqla riyazi əməliyyatlar üçün təlimat çıxarmaq, registrlərdən düzgün dəyərləri götürmək kimi şeylər - bütün bunlar bir anda edilir. Siz bunu edərkən beyninizə həkk olunacaq. Düşünürəm ki, hamı kompilyatorun nə etdiyini bilir. Və bu, xərc modeli haqqında anlayış verəcəkdir.

Performansın yaxşılaşdırılmasının praktiki nümunələri

Andrew: Məhsuldarlıq üzərində işləyərkən daha nələrə diqqət etməlisiniz?

Uçurum: Məlumat strukturları. Yeri gəlmişkən, bəli, mən çoxdandır ki, bu dərsləri öyrətmirəm... Raket məktəbi. Əyləncəli idi, amma çox səy tələb etdi və mənim də həyatım var! TAMAM. Beləliklə, böyük və maraqlı dərslərdən birində “Performansınız hara gedir” mövzusunda tələbələrə bir nümunə verdim: CSV faylından iki yarım gigabaytlıq fintech məlumatları oxundu və sonra onlar satılan məhsulların sayını hesablamalı oldular. . Daimi gənə bazarı məlumatları. UDP paketləri 70-ci illərdən mətn formatına çevrildi. Çikaqo Ticarət Birjası - kərə yağı, qarğıdalı, soya fasulyesi kimi hər cür şeylər. Bu məhsulları, əməliyyatların sayını, vəsaitlərin və malların hərəkətinin orta həcmini və s. saymaq lazım idi. Bu olduqca sadə ticarət riyaziyyatıdır: məhsul kodunu tapın (həş cədvəlində 1-2 simvoldur), məbləği əldə edin, ticarət dəstlərindən birinə əlavə edin, həcm əlavə edin, dəyər əlavə edin və bir neçə başqa şey. Çox sadə riyaziyyat. Oyuncağın həyata keçirilməsi çox sadə idi: hər şey bir fayldadır, mən faylı oxudum və orada hərəkət etdim, fərdi qeydləri Java sətirlərinə böldüm, onlarda lazımi şeyləri axtardım və yuxarıda təsvir olunan riyaziyyata uyğun olaraq əlavə etdim. Və bəzi aşağı sürətlə işləyir.

Bu yanaşma ilə nə baş verdiyi aydındır və paralel hesablamalar kömək etməyəcək, elə deyilmi? Belə çıxır ki, performansın beş qat artmasına sadəcə düzgün məlumat strukturlarını seçməklə nail olmaq olar. Və bu hətta təcrübəli proqramçıları da təəccübləndirir! Mənim xüsusi vəziyyətimdə hiylə ondan ibarət idi ki, siz isti döngədə yaddaş ayırmamalısınız. Bəli, bu, bütün həqiqət deyil, amma ümumiyyətlə - X kifayət qədər böyük olduqda "X-də bir dəfə" vurğulamamalısınız. X iki yarım gigabayt olduqda, siz “hər hərfdə bir dəfə”, “hər sətirdə bir dəfə” və ya “hər sahəyə bir dəfə”, buna bənzər heç bir şey ayırmamalısınız. Burada vaxt sərf olunur. Bu hətta necə işləyir? Təsəvvür edin ki, mən zəng edirəm String.split() və ya BufferedReader.readLine(). Readline şəbəkə üzərindən gələn bayt dəstindən yüz milyonlarla sətirin hər biri üçün hər sətir üçün bir dəfə sətir düzəldir. Mən bu xətti götürürəm, təhlil edirəm və atıram. Niyə onu atıram - yaxşı, mən artıq emal etmişəm, hamısı budur. Beləliklə, bu 2.7G-dən oxunan hər bayt üçün sətirdə iki simvol yazılacaq, yəni artıq 5.4G və onlara əlavə heç nə lazım deyil, buna görə də atılır. Yaddaş ötürmə qabiliyyətinə baxsanız, biz prosessorda yaddaş və yaddaş avtobusundan keçən 2.7G yükləyirik, sonra isə yaddaşda yatan xəttə iki dəfə çox göndərilir və hər yeni sətir yarananda bütün bunlar köhnəlir. Amma oxumalıyam, sonradan hər şey köhnəlisə belə, aparat onu oxuyur. Və mən onu yazmalıyam, çünki bir xətt yaratdım və önbelleklər doludur - keş 2.7G-ni yerləşdirə bilməz. Beləliklə, oxuduğum hər bayt üçün daha iki bayt oxuyuram və daha iki bayt yazıram və sonda onlar 4:1 nisbətinə malikdirlər - bu nisbətdə yaddaşın ötürmə qabiliyyətini israf edirik. Və sonra belə çıxır ki, etsəm String.split() – bunu sonuncu dəfə etmirəm, içəridə daha 6-7 sahə ola bilər. Beləliklə, CSV-ni oxumaq və sonra sətirləri təhlil etmək üçün klassik kod əslində sahib olmaq istədiyinizə nisbətən təxminən 14:1 yaddaş bant genişliyi itkisi ilə nəticələnir. Bu seçimləri atsanız, beşqat sürət əldə edə bilərsiniz.

Və o qədər də çətin deyil. Koda düzgün bucaqdan baxsanız, problemi dərk etdikdən sonra hər şey olduqca sadə olacaq. Yaddaşın ayrılmasını tamamilə dayandırmamalısınız: yeganə problem odur ki, siz nəyisə ayırırsınız və o, dərhal ölür və bu zaman yaddaşın ötürmə qabiliyyəti olan mühüm resursu yandırır. Və bütün bunlar məhsuldarlığın azalması ilə nəticələnir. X86-da adətən prosessor dövrələrini aktiv şəkildə yandırmaq lazımdır, lakin burada bütün yaddaşı çox əvvəl yandırmısınız. Həll yolu boşalma miqdarını azaltmaqdır. 
Problemin digər tərəfi ondan ibarətdir ki, yaddaş zolağı bitəndə profili işlədirsinizsə, bu baş verəndə siz adətən keşin geri qayıtmasını gözləyirsiniz, çünki o, indicə istehsal etdiyiniz zibillə, bütün bu xətlərlə doludur. Buna görə də, hər bir yükləmə və ya mağaza əməliyyatı yavaş olur, çünki onlar önbellek itkilərinə səbəb olur - bütün önbellek yavaş olur, zibilin onu tərk etməsini gözləyir. Buna görə də, profilçi yalnız bütün döngəyə bulaşan isti təsadüfi səs-küy göstərəcək - kodda ayrıca isti təlimat və ya yer olmayacaq. Yalnız səs-küy. Əgər GC dövrlərinə baxsanız, onların hamısı Gənc Nəsildir və super sürətlidir - maksimum mikrosaniyələr və ya millisaniyələr. Axı bütün bu yaddaş anında ölür. Siz milyardlarla gigabayt ayırırsınız, o da onları kəsir, kəsir və yenidən kəsir. Bütün bunlar çox tez baş verir. Belə çıxır ki, ucuz GC dövrləri, bütün dövr ərzində isti səs-küy var, lakin biz 5x sürətlənmə əldə etmək istəyirik. Bu anda beyninizdə bir şey bağlanmalı və səslənməlidir: "bu niyə belədir?!" Yaddaş zolağının daşması klassik sazlayıcıda göstərilmir; siz aparat performansı sayğacını işə salmalı və ona özünüz və birbaşa baxmalısınız. Ancaq bu üç əlamətdən birbaşa şübhələnmək olmaz. Üçüncü əlamət, vurğuladığınız şeyə baxdığınız zaman profilçidən soruşun və o cavab verir: "Bir milyard cərgə yaratdınız, lakin GC pulsuz işlədi." Bu baş verən kimi siz həddən artıq çox obyekt yaratdığınızı və bütün yaddaş zolağınızı yandırdığınızı başa düşürsünüz. Bunu anlamaq üçün bir yol var, amma açıq deyil. 

Problem məlumat strukturundadır: baş verən hər şeyin altında yatan çılpaq struktur, çox böyükdür, diskdə 2.7G-dir, ona görə də bu şeyin surətini çıxarmaq çox arzuolunmazdır - onu dərhal şəbəkə bayt buferindən yükləmək istəyirsiniz. registrlərə beş dəfə irəli-geri oxumaq-yazmamaq üçün. Təəssüf ki, Java sizə standart olaraq JDK-nın bir hissəsi kimi belə bir kitabxana vermir. Ancaq bu əhəmiyyətsizdir, elə deyilmi? Əsasən, bunlar sətir sinifinin davranışını təkrarlayan və əsas bayt buferi ətrafında sarğı olan öz tamponlanmış sətir yükləyicinizi həyata keçirmək üçün istifadə olunacaq 5-10 kod sətiridir. Nəticədə məlum olur ki, siz az qala sətirlərlə işləyirsiniz, amma əslində buferin göstəriciləri orada hərəkət edir və xam baytlar heç bir yerə kopyalanmır və beləliklə, eyni buferlər təkrar-təkrar istifadə olunur və əməliyyat sistemi bu bayt buferlərinin gizli ikiqat tamponlanması kimi nəzərdə tutulduğu şeyləri öz üzərinə götürməkdən məmnundur və siz artıq lazımsız məlumatların sonsuz axını ilə məşğul olmursunuz. Yeri gəlmişkən, başa düşürsünüz ki, GC ilə işləyərkən, hər bir yaddaş ayrılması son GC dövründən sonra prosessor üçün görünməyəcəkdir? Buna görə də, bütün bunlar önbellekdə ola bilməz və sonra 100% zəmanətli qaçırma baş verir. Göstərici ilə işləyərkən, x86-da, yaddaşdan registri çıxarmaq 1-2 saat dövrünü alır və bu baş verən kimi siz ödəyirsiniz, ödəyirsiniz, ödəyirsiniz, çünki yaddaş hamısı aktivdir. NINE keş – və bu yaddaşın ayrılması dəyəridir. Real dəyər.

Başqa sözlə, məlumat strukturlarını dəyişdirmək ən çətin şeydir. Və sonradan performansı öldürəcək yanlış məlumat strukturunu seçdiyinizi dərk etdikdən sonra, adətən görüləcək çox iş var, lakin bunu etməsəniz, işlər daha da pisləşəcək. İlk növbədə, məlumat strukturları haqqında düşünmək lazımdır, bu vacibdir. Burada əsas xərc “Y-nin formasını daha çox bəyəndiyim üçün X məlumat strukturunu Y məlumat strukturuna köçürdüm” üslubunda istifadə olunmağa başlayan yağ məlumat strukturlarına düşür. Lakin kopyalama əməliyyatı (ucuz görünən) əslində yaddaşın ötürücülük qabiliyyətini itirir və bütün boşa çıxan icra vaxtı orada basdırılır. Əgər məndə nəhəng bir JSON sətri varsa və onu POJO-ların strukturlaşdırılmış DOM ağacına və ya başqa bir şeyə çevirmək istəsəm, həmin sətirin təhlili və POJO-nun qurulması əməliyyatı və sonra yenidən POJO-ya daxil olmaq lazımsız xərclərlə nəticələnəcək - bu ucuz deyil. Əgər POJO-ların ətrafında bir simin ətrafında qaçdığınızdan daha tez-tez qaçırsınızsa. Əlbətdə ki, bunun əvəzinə sətri deşifrə etməyə və onu heç bir POJO-ya çevirmədən yalnız lazım olanı oradan çıxarmağa cəhd edə bilərsiniz. Bütün bunlar maksimum performans tələb olunan bir yolda baş verərsə, sizin üçün heç bir POJO yoxdur, birtəhər birbaşa xətti qazmalısınız.

Niyə öz proqramlaşdırma dilinizi yaradın

Andrew: Siz dediniz ki, xərc modelini başa düşmək üçün öz kiçik dilinizi yazmalısınız...

Uçurum: Dil deyil, kompilyatordur. Dil və tərtibçi iki fərqli şeydir. Ən əhəmiyyətli fərq başınızdadır. 

Andrew: Yeri gəlmişkən, bildiyimə görə, siz öz dillərinizi yaratmaq üçün təcrübə aparırsınız. Nə üçün?

Uçurum: Çünki mən bacarıram! Mən yarı təqaüdçüyəm, ona görə də bu mənim hobbimdir. Mən bütün həyatım boyu başqa insanların dillərini tətbiq etmişəm. Kodlaşdırma tərzim üzərində də çox işləmişəm. Həm də ona görə ki, başqa dillərdə problemlər görürəm. Görürəm ki, tanış işlərlə məşğul olmaq üçün daha yaxşı yollar var. Və mən onlardan istifadə edərdim. Sadəcə özümdə, Java-da, Python-da, hər hansı başqa dildə problemlər görməkdən bezmişəm. İndi mən React Native, JavaScript və Elm dillərində təqaüdə çıxmaq üçün deyil, aktiv iş haqqında hobbi kimi yazıram. Mən də Python-da yazıram və çox güman ki, Java backendləri üçün maşın öyrənməsi üzərində işləməyə davam edəcəyəm. Çox populyar dillər var və hamısının maraqlı xüsusiyyətləri var. Hər kəs öz yolunda yaxşıdır və bütün bu xüsusiyyətləri bir araya gətirməyə cəhd edə bilərsiniz. Beləliklə, məni maraqlandıran şeyləri, dilin davranışını öyrənirəm, ağlabatan semantika ilə çıxış etməyə çalışıram. Və indiyə qədər uğur qazanıram! Hal-hazırda yaddaş semantikası ilə mübarizə aparıram, çünki C və Java-da olduğu kimi buna sahib olmaq və yükləmələr və mağazalar üçün güclü yaddaş modeli və yaddaş semantikası əldə etmək istəyirəm. Eyni zamanda, Haskelldəki kimi avtomatik tipli nəticəyə sahib olun. Burada mən Haskell tipli nəticəni həm C, həm də Java-da yaddaş işi ilə qarışdırmağa çalışıram. Məsələn, son 2-3 ayda etdiyim şey budur.

Andrew: Başqa dillərdən daha yaxşı cəhətləri götürən bir dil qursanız, kimsə bunun əksini edəcəkmi: fikirlərinizi götürüb istifadə edəcəksiniz?

Uçurum: Yeni dillər məhz belə görünür! Java niyə C ilə oxşardır? Çünki C hər kəsin başa düşdüyü yaxşı sintaksisə malik idi və Java bu sintaksisdən ilhamlanaraq tip təhlükəsizliyi, massiv sərhədlərinin yoxlanılması, GC əlavə edildi və onlar C-dən bəzi şeyləri təkmilləşdirdilər. Özlərini əlavə etdilər. Ancaq çox ilham aldılar, elə deyilmi? Hamı sizdən əvvəl gələn nəhənglərin çiynində dayanır - beləcə irəliləyiş əldə edilir.

Andrew: Mən başa düşdüyüm kimi, diliniz yaddaşda təhlükəsiz olacaq. Rust-dan borc yoxlaması kimi bir şey tətbiq etməyi düşünmüsünüzmü? Ona baxmısan, onun haqqında nə düşünürsən?

Uçurum: Yaxşı, mən bütün bu malloc və pulsuz ilə əsrlərdir C yazıram və ömür boyu əl ilə idarə edirəm. Bilirsiniz, əl ilə idarə olunan ömür müddətinin 90-95%-i eyni quruluşa malikdir. Və bunu əl ilə etmək çox, çox ağrılıdır. Mən istərdim ki, tərtibçi sizə orada nə baş verdiyini və hərəkətlərinizlə nəyə nail olduğunuzu izah etsin. Bəzi şeylər üçün borc yoxlaması bunu qutudan kənarda edir. Və o, avtomatik olaraq məlumatları göstərməli, hər şeyi başa düşməlidir və hətta bu anlayışı təqdim etməklə məni yükləməməlidir. O, ən azı yerli qaçış təhlili etməlidir və yalnız uğursuz olarsa, ömrünü təsvir edəcək tip annotasiyaları əlavə etməlidir - və belə bir sxem borc yoxlayıcısından və ya həqiqətən də hər hansı mövcud yaddaş yoxlayıcısından daha mürəkkəbdir. "Hər şey yaxşıdır" və "Mən heç nə başa düşmürəm" arasında seçim - yox, daha yaxşı bir şey olmalıdır. 
Beləliklə, C-də çoxlu kod yazan biri kimi düşünürəm ki, avtomatik ömür boyu nəzarət dəstəyinin olması ən vacib şeydir. Java-nın yaddaşdan nə qədər istifadə etməsindən də bezmişəm və əsas şikayət GC-dir. Java-da yaddaş ayırdığınız zaman son GC dövründə yerli olan yaddaşı geri ala bilməyəcəksiniz. Daha dəqiq yaddaş idarəçiliyi olan dillərdə bu belə deyil. Əgər malloc-a zəng etsəniz, dərhal istifadə olunan yaddaşı alırsınız. Adətən yaddaşla bəzi müvəqqəti işlər görürsən və dərhal onu geri qaytarırsan. Və dərhal malloc hovuzuna qayıdır və növbəti malloc dövrü onu yenidən çıxarır. Buna görə də, faktiki yaddaş istifadəsi müəyyən bir zamanda canlı obyektlər dəstinə, üstəgəl sızmalara endirilir. Və hər şey tamamilə ləyaqətsiz bir şəkildə sızmazsa, yaddaşın çoxu önbelleklərdə və prosessorda sona çatır və tez işləyir. Lakin malloc və pulsuz ilə düzgün qaydada, doğru yerdə çağırılan çoxlu əl yaddaşının idarə edilməsi tələb olunur. Rust bunu öz başına düzgün şəkildə idarə edə bilər və bir çox hallarda daha yaxşı performans göstərə bilər, çünki yaddaş istehlakı yalnız cari hesablamaya endirilir - yaddaşı boşaltmaq üçün növbəti GC dövrəsini gözləməkdən fərqli olaraq. Nəticədə performansı yaxşılaşdırmaq üçün çox maraqlı bir yol əldə etdik. Və kifayət qədər güclü - demək istəyirəm ki, mən fintech üçün məlumatları emal edərkən belə şeylər etdim və bu, mənə təxminən beş dəfə sürətlənməyə imkan verdi. Bu, xüsusilə prosessorların sürətlənmədiyi və hələ də təkmilləşdirmələri gözlədiyimiz bir dünyada olduqca böyük təkandır.

Performans Mühəndisi Karyera

Andrew: Mən də ümumiyyətlə karyera haqqında soruşmaq istərdim. Siz HotSpot-da JIT işinizlə şöhrət qazandınız və sonra JVM şirkəti olan Azul-a keçdiniz. Amma biz artıq proqram təminatından daha çox aparat üzərində işləyirdik. Və sonra birdən Big Data və Machine Learning-ə, sonra isə fırıldaqçılığın aşkarlanmasına keçdilər. Bu necə oldu? Bunlar çox fərqli inkişaf sahələridir.

Uçurum: Mən kifayət qədər uzun müddət proqramlaşdırma ilə məşğul olmuşam və bir çox müxtəlif dərsləri keçməyi bacarmışam. İnsanlar dedikdə: “Oh, Java üçün JIT edən sənsən!”, həmişə gülməli olur. Amma bundan əvvəl mən PostScript-in klonu üzərində işləyirdim - Apple-ın vaxtilə lazer printerləri üçün istifadə etdiyi dil. Bundan əvvəl mən dördüncü dilin tətbiqini etdim. Düşünürəm ki, mənim üçün ümumi mövzu alət inkişafıdır. Bütün həyatım boyu mən digər insanların gözəl proqramlarını yazdıqları alətlər hazırlamışam. Lakin mən həm də əməliyyat sistemlərinin, drayverlərin, nüvə səviyyəli sazlayıcıların, ƏS-nin inkişafı üçün dillərin hazırlanmasında iştirak etmişəm, hansı ki, əvvəllər mənasız başlayan, lakin zaman keçdikcə daha da mürəkkəbləşdi. Ancaq əsas mövzu hələ də alətlərin inkişafıdır. Həyatımın böyük bir hissəsi Azul və Sun arasında keçdi və Java haqqında idi. Amma mən Böyük Məlumat və Maşın Öyrənməsinə daxil olanda dəbdəbəli papağımı yenidən taxdım və dedim: “Oh, indi bizim qeyri-ciddi bir problemimiz var və çox maraqlı şeylər baş verir və insanlar bir şey edir.” Bu, böyük inkişaf yoludur.

Bəli, mən paylanmış hesablamaları çox sevirəm. İlk işim C-də bir reklam layihəsində tələbə kimi oldu. Bu, əsl analoq analizator tərəfindən istehsal olunan analoq OCR üçün məlumat toplayan Zilog Z80 çiplərində hesablamalar paylanmışdır. Sərin və tamamilə çılğın mövzu idi. Ancaq problemlər var idi, bəzi hissələr düzgün tanınmadı, ona görə də bir şəkil çıxarıb onu gözləri ilə oxuya bilən və dediklərini bildirə bilən bir şəxsə göstərmək lazım idi və buna görə də data ilə iş var idi və bu işlər öz dili var idi. Bütün bunları emal edən bir backend var idi - Vt80 terminalları ilə paralel işləyən Z100-lər - adam başına bir və Z80-də paralel proqramlaşdırma modeli var idi. Ulduz konfiqurasiyası daxilində bütün Z80-lər tərəfindən paylaşılan bəzi ümumi yaddaş parçası; Arxa plan da paylaşıldı və RAM-in yarısı şəbəkə daxilində paylaşıldı, digər yarısı isə özəl idi və ya başqa bir şeyə getdi. Paylaşılan... yarı paylaşılan yaddaşa malik mənalı mürəkkəb paralel paylanmış sistem. Bu nə vaxt idi... Heç yadımda deyil, haradasa 80-ci illərin ortalarında. Çox uzun müddət əvvəl. 
Bəli, tutaq ki, 30 il kifayət qədər uzun müddətdir, paylanmış hesablama ilə bağlı problemlər kifayət qədər uzun müddətdir mövcuddur, insanlar çoxdan onlarla müharibə aparırlar. Beowulf-klasterlər. Belə klasterlər belə görünür... Məsələn: Ethernet var və sürətli x86-nız bu Ethernet-ə qoşulub və indi siz saxta paylaşılan yaddaş əldə etmək istəyirsiniz, çünki o vaxt heç kim paylanmış hesablama kodlamasını edə bilməzdi, bu çox çətin idi və buna görə də orada x86-da qorunan yaddaş səhifələri ilə saxta paylaşılan yaddaş idi və bu səhifəyə yazsanız, o zaman biz digər prosessorlara dedik ki, əgər onlar eyni paylaşılan yaddaşa daxil olarsa, o, sizdən yüklənməlidir və beləliklə, dəstək üçün protokol kimi bir şey olacaq. cache coherence ortaya çıxdı və bunun üçün proqram təminatı. Maraqlı konsepsiya. Əsl problem, təbii ki, başqa şeydi. Bütün bunlar işlədi, lakin siz tez bir zamanda performans problemləri ilə üzləşdiniz, çünki heç kim performans modellərini kifayət qədər yaxşı səviyyədə başa düşmədi - orada hansı yaddaşa giriş nümunələri var, qovşaqların bir-birinə sonsuz ping atmamasına necə əmin olmaq olar və s.

H2O-da əldə etdiyim şey, paralelliyin harada gizləndiyini və harada olmadığını müəyyən etmək üçün məsul olan tərtibatçıların özləridir. Mən yüksək performanslı kodu yazmağı asan və sadə edən bir kodlaşdırma modeli ilə gəldim. Amma yavaş işləyən kodu yazmaq çətindir, pis görünəcək. Yavaş kod yazmağa ciddi cəhd etməlisiniz, qeyri-standart üsullardan istifadə etməli olacaqsınız. Əyləc kodu ilk baxışdan görünür. Nəticədə, siz adətən sürətli işləyən kod yazırsınız, lakin paylaşılan yaddaş vəziyyətində nə edəcəyinizi anlamaq məcburiyyətindəsiniz. Bütün bunlar böyük massivlərə bağlıdır və oradakı davranış paralel Java-da uçucu olmayan böyük massivlərə bənzəyir. Təsəvvür edin ki, iki mövzu paralel massiləyə yazır, onlardan biri qalib gəlir, digəri isə müvafiq olaraq uduzur və siz hansının hansı olduğunu bilmirsiniz. Əgər onlar dəyişkən deyillərsə, onda sifariş istədiyiniz hər şey ola bilər - və bu, həqiqətən yaxşı işləyir. İnsanlar əməliyyatların ardıcıllığına həqiqətən əhəmiyyət verirlər, dəyişkənliyi düzgün yerlərə qoyurlar və lazımi yerlərdə yaddaşla bağlı performans problemləri gözləyirlər. Əks halda, onlar sadəcə kodu 1-dən N-ə qədər döngələr şəklində yazacaqdılar, burada N bir neçə trilyondur, ümidlə bütün mürəkkəb hallar avtomatik olaraq paralel olacaq - və orada işləmir. Lakin H2O-da bu nə Java, nə də Scala deyil; istəsəniz, onu “Java minus minus” hesab edə bilərsiniz. Bu, çox aydın proqramlaşdırma tərzidir və sadə C və ya Java kodunu döngələr və massivlərlə yazmağa bənzəyir. Ancaq eyni zamanda, yaddaş terabaytlarla işlənə bilər. Mən hələ də H2O istifadə edirəm. Mən onu zaman-zaman müxtəlif layihələrdə istifadə edirəm - və bu, hələ də ən sürətli şeydir, rəqiblərindən onlarla dəfə daha sürətli. Sütunlu məlumatlarla Big Data edirsinizsə, H2O-nu məğlub etmək çox çətindir.

Texniki Çağırışlar

Andrew: Bütün karyeranızda ən böyük probleminiz nə olub?

Uçurum: Biz məsələnin texniki və ya qeyri-texniki hissəsini müzakirə edirik? Mən deyərdim ki, ən böyük çətinliklər texniki problemlər deyil. 
Texniki çətinliklərə gəlincə. Mən onları sadəcə məğlub etdim. Ən böyüyünün nə olduğunu belə bilmirəm, amma kifayət qədər vaxt aparan, zehni mübarizə aparan olduqca maraqlı olanlar var idi. Günəşə getdiyim zaman sürətli kompilyator hazırlayacağıma əmin idim və bir dəstə böyüklər cavab olaraq heç vaxt uğur qazana bilməyəcəyimi söylədilər. Ancaq mən bu yolu izlədim, registr ayırıcısına bir kompilyator yazdım və bu, olduqca sürətli idi. O, müasir C1 qədər sürətli idi, lakin o zaman ayırıcı daha yavaş idi və arxa planda bu, böyük bir məlumat strukturu problemi idi. Qrafik registr ayırıcısını yazmaq üçün mənə lazım idi və o dövrdə mövcud olan və çox vacib olan kodun ifadəliliyi ilə sürət arasındakı dilemmanı başa düşmədim. Məlum oldu ki, məlumat strukturu adətən o dövrün x86-larda keş ölçüsünü üstələyir və buna görə də əvvəlcə registr ayırıcısının ümumi titrəmə vaxtının 5-10 faizini işləyəcəyini güman edirdimsə, əslində belə oldu. 50 faiz.

Zaman keçdikcə kompilyator daha təmiz və səmərəli oldu, daha çox hallarda dəhşətli kod yaratmağı dayandırdı və performans getdikcə C kompilyatorunun istehsal etdiyinə bənzəməyə başladı.Əgər, əlbəttə ki, hətta C-nin də sürətləndirməyəcəyi bir şey yazmasanız. . C kimi kod yazsanız, daha çox hallarda C kimi performans əldə edəcəksiniz. Və nə qədər irəli getsəniz, asimptotik olaraq C səviyyəsi ilə üst-üstə düşən kodu bir o qədər tez-tez alırsınız, registr ayırıcısı tam bir şey kimi görünməyə başladı... kodunuzun sürətli və ya yavaş işləməsindən asılı olmayaraq. Daha yaxşı seçimlər etmək üçün ayırıcı üzərində işləməyə davam etdim. O, daha yavaş və yavaş oldu, lakin heç kimin öhdəsindən gələ bilmədiyi hallarda daha yaxşı və daha yaxşı performans göstərdi. Mən registr ayırıcısına daxil ola bilərdim, bir aylıq işi orada basdıra bilərdim və birdən bütün kod 5% daha sürətli icra etməyə başlayacaqdı. Bu dəfələrlə baş verdi və reyestr ayıran bir sənət əsərinə çevrildi - hamı onu sevdi və ya nifrət etdi və akademiyadan gələnlər "niyə hər şey belə edilir" mövzusunda suallar verdilər. xətt tarama, və nə fərqi var. Cavab hələ də eynidir: qrafik təsvirinə əsaslanan ayırıcı və bufer kodu ilə çox diqqətli işləmək qələbə silahına bərabərdir, heç kimin məğlub edə bilməyəcəyi ən yaxşı birləşmədir. Və bu olduqca qeyri-aşkar bir şeydir. Tərtibçinin etdiyi hər şey kifayət qədər yaxşı öyrənilmiş şeylərdir, baxmayaraq ki, onlar da sənət səviyyəsinə çatdırılmışdır. Mən həmişə tərtibçini sənət əsərinə çevirməli olan işlər görmüşəm. Ancaq bunların heç biri qeyri-adi bir şey deyildi - reyestr ayırıcıdan başqa. Hiylə ehtiyatlı olmaqdır ixtisar etmək yük altında və bu baş verərsə (maraqlansanız daha ətraflı izah edə bilərəm), bu o deməkdir ki, siz performans cədvəlində əyilmə riski olmadan daha aqressiv şəkildə sıraya daxil ola bilərsiniz. O günlərdə bir dəstə tam miqyaslı tərtibatçılar var idi, çubuqlar və fitlər asılmış, registr ayırıcıları var idi, lakin başqa heç kim bunu edə bilməzdi.

Məsələ ondadır ki, içəriyə daxil olan, daxili xətti artıran və artıran metodlar əlavə etsəniz, istifadə olunan dəyərlər dəsti registrlərin sayını dərhal üstələyir və siz onları kəsməlisiniz. Kritik səviyyə adətən ayırıcı imtina etdikdə gəlir və bir dağılma üçün yaxşı bir namizəd digərinə dəyər, siz ümumiyyətlə vəhşi şeyləri satacaqsınız. Bura daxil etməyin dəyəri ondan ibarətdir ki, siz zəng və qənaət üçün əlavə xərclərin bir hissəsini itirirsiniz, içəridəki dəyərləri görə bilərsiniz və onları daha da optimallaşdıra bilərsiniz. Daxil etmə dəyəri ondan ibarətdir ki, çoxlu sayda canlı dəyərlər əmələ gəlir və reyestr ayırıcınız lazım olduğundan daha çox yanırsa, dərhal itirirsiniz. Buna görə də, əksər ayırıcıların bir problemi var: inlining müəyyən bir xətti keçdikdə, dünyada hər şey kəsilməyə başlayır və məhsuldarlıq tualetə tökülə bilər. Kompilyatoru həyata keçirənlər bəzi evristikanı əlavə edirlər: məsələn, kifayət qədər böyük ölçüdən başlayaraq daxil etməyi dayandırmaq, çünki ayırmalar hər şeyi məhv edəcəkdir. Performans qrafikində bir əyilmə belə yaranır - siz inline, inline, performans yavaş-yavaş artır - və sonra bum! – həddən artıq sıraya girdiyiniz üçün cəld jak kimi düşür. Java-nın yaranmasından əvvəl hər şey belə işləyirdi. Java daha çox daxil etməyi tələb edir, ona görə də mən ayırıcımı daha aqressiv etməli oldum ki, o, qəzaya düşməkdənsə, səviyyəni aşağı salsın və siz çox satırsanız, tökülməyə başlayır, lakin sonra “daha ​​tökülmə” anı hələ də gəlir. Bu maraqlı bir müşahidədir və o, heç bir yerdən mənə gəldi, aşkar deyil, amma yaxşı nəticə verdi. Mən aqressiv daxil etməyə başladım və bu, məni Java və C performansının yan-yana işlədiyi yerlərə apardı. Onlar həqiqətən yaxındırlar - mən C kodundan və buna bənzər şeylərdən əhəmiyyətli dərəcədə sürətli Java kodu yaza bilərəm, lakin orta hesabla, hər şeyin böyük mənzərəsində onlar təxminən müqayisə edilə bilər. Düşünürəm ki, bu ləyaqətin bir hissəsi mənə mümkün qədər axmaq şəkildə daxil olmağa imkan verən reyestr ayırıcısıdır. Mən sadəcə gördüyüm hər şeyi satıram. Burada sual, ayırıcının yaxşı işləməsi, nəticənin ağıllı şəkildə işləyən kodu olub-olmamasıdır. Bu, böyük bir problem idi: bütün bunları başa düşmək və işləmək.

Qeydiyyatın ayrılması və çox nüvəli haqqında bir az

Vladimir: Reyestrlərin ayrılması kimi problemlər bir növ əbədi, sonsuz mövzu kimi görünür. Maraqlıdır, nə vaxtsa perspektivli görünən, sonra isə praktikada uğursuzluğa düçar olan ideya olubmu?

Uçurum: Əlbəttə! Qeydiyyatın ayrılması NP-tam problemi həll etmək üçün bəzi evristik üsulları tapmağa çalışdığınız sahədir. Və heç vaxt mükəmməl bir həllə nail ola bilməzsiniz, elə deyilmi? Bu, sadəcə olaraq mümkün deyil. Baxın, Ahead of Time kompilyasiyası - o da zəif işləyir. Burada söhbət bəzi orta hallardan gedir. Tipik performans haqqında, belə ki, gedib yaxşı tipik performans hesab etdiyiniz bir şeyi ölçə bilərsiniz - axırda siz onu təkmilləşdirməyə çalışırsınız! Qeydiyyatın ayrılması bütün performansla bağlı bir mövzudur. İlk prototipə sahib olduqdan sonra o, işləyir və lazım olanı rəngləyir, performans işi başlayır. Yaxşı ölçməyi öyrənmək lazımdır. Niyə vacibdir? Əgər aydın məlumatınız varsa, müxtəlif sahələrə baxıb görə bilərsiniz: bəli, burada kömək etdi, amma hər şey burada pozuldu! Bəzi yaxşı fikirlər ortaya çıxır, siz yeni evristika əlavə edirsiniz və birdən hər şey orta hesabla bir az daha yaxşı işləməyə başlayır. Yoxsa başlamır. İnkişafımızı əvvəlki paylayıcıdan fərqləndirən beş faizlik performans üçün mübarizə apardığımız bir çox hallarım var idi. Və hər dəfə belə görünür: hardasa qalib gəlirsən, hardasa uduzursan. Yaxşı performans təhlili alətləriniz varsa, itirilən fikirləri tapa və niyə uğursuz olduğunu başa düşə bilərsiniz. Ola bilsin ki, hər şeyi olduğu kimi buraxmağa, ya da incə tənzimləməyə daha ciddi yanaşmağa, ya da çıxıb başqa bir şeyi düzəltməyə dəyər. Bu bir çox şeydir! Mən bu gözəl hack etdim, amma mənə bu, bu, və bu lazımdır - və onların ümumi birləşməsi bəzi təkmilləşdirmələr verir. Və təklər uğursuz ola bilər. Bu, NP-tam problemlərlə bağlı icra işinin xarakteridir.

Vladimir: İnsanda belə bir hiss yaranır ki, ayırıcılarda rəsm çəkmək kimi şeylər artıq həll olunmuş problemdir. Bəli, dediklərinizə görə qərar verdiniz, o zaman buna dəyərmi...

Uçurum: Belə həll olunmur. Onu “həll edilmiş”ə çevirməli olan sizsiniz. Çətin problemlər var və onları həll etmək lazımdır. Bunu etdikdən sonra məhsuldarlıq üzərində işləməyin vaxtı gəldi. Bu işə uyğun yanaşmaq lazımdır - müqayisələr aparın, ölçülər toplayın, əvvəlki versiyaya qayıtdığınız zaman köhnə hackiniz yenidən işə başladığında (və ya əksinə, dayandıqda) vəziyyətləri izah edin. Və nəyəsə nail olana qədər təslim olmayın. Artıq dediyim kimi, işləməyən sərin ideyalar varsa, lakin ideyaların reyestrlərinin bölüşdürülməsi sahəsində bu, təxminən sonsuzdur. Məsələn, elmi nəşrləri oxuya bilərsiniz. Baxmayaraq ki, indi bu sahə çox yavaş hərəkət etməyə başlayıb və gəncliyindən daha aydınlaşıb. Bununla belə, bu sahədə çalışan saysız-hesabsız insanlar var və onların bütün ideyaları sınamağa dəyər, hamısı qanadda gözləyir. Onları sınamasanız, onların nə qədər yaxşı olduğunu deyə bilməzsiniz. Onlar ayırıcınızdakı hər şeylə nə qədər yaxşı inteqrasiya edirlər, çünki ayırıcı çox şey edir və bəzi ideyalar sizin xüsusi ayırıcınızda işləməyəcək, lakin başqa ayırıcıda asanlıqla işləyəcək. Ayırıcı üçün qazanmağın əsas yolu, yavaş materialı əsas yoldan kənara çəkmək və onu yavaş yolların sərhədləri boyunca parçalamağa məcbur etməkdir. Beləliklə, əgər siz GC-ni idarə etmək istəyirsinizsə, yavaş yolu seçin, deoptimallaşdırın, bir istisna atın, bütün bu şeylər - bilirsiniz ki, bunlar nisbətən nadirdir. Və onlar həqiqətən nadirdir, yoxladım. Siz əlavə iş görürsünüz və bu, bu yavaş yollardakı bir çox məhdudiyyətləri aradan qaldırır, lakin bu, çox yavaş və nadir hallarda səyahət etdikləri üçün əhəmiyyət kəsb etmir. Məsələn, null göstərici - bu heç vaxt baş vermir, elə deyilmi? Fərqli şeylər üçün bir neçə yolun olması lazımdır, lakin onlar əsas birinə müdaxilə etməməlidir. 

Vladimir: Bir anda minlərlə nüvə olduqda, çox nüvəlilər haqqında nə düşünürsünüz? Bu faydalı bir şeydir?

Uçurum: GPU-nun uğuru onun olduqca faydalı olduğunu göstərir!

Vladimir: Onlar kifayət qədər ixtisaslaşmışdırlar. Ümumi təyinatlı prosessorlar haqqında nə demək olar?

Uçurum: Bu Azulun biznes modeli idi. Cavab insanların proqnozlaşdırıla bilən performansı həqiqətən sevdiyi bir dövrdə gəldi. O vaxtlar paralel kod yazmaq çətin idi. H2O kodlaşdırma modeli yüksək dərəcədə genişlənə bilir, lakin ümumi məqsədli model deyil. Ola bilsin ki, bir GPU istifadə edərkən bir az daha ümumi. Söhbət belə bir şeyin inkişafının mürəkkəbliyindən və ya ondan istifadənin mürəkkəbliyindən gedir? Məsələn, Azul mənə maraqlı bir dərs verdi, olduqca qeyri-aşkar: kiçik yaddaşlar normaldır. 

Həyatda ən böyük sınaq

Vladimir: Qeyri-texniki problemlər haqqında nə demək olar?

Uçurum: Ən böyük problem insanlara qarşı mehriban və xeyirxah olmamaq idi. Və nəticədə özümü daim son dərəcə münaqişəli vəziyyətlərdə tapdım. Mən hər şeyin səhv getdiyini bildiyim, lakin bu problemlərlə necə irəliləyəcəyimi bilmədiyim və onları idarə edə bilmədiyim insanlar. Onilliklər boyu davam edən bir çox uzunmüddətli problemlər bu şəkildə yarandı. Java-da C1 və C2 kompilyatorlarının olması bunun birbaşa nəticəsidir. Java-da on il ardıcıl olaraq çoxsəviyyəli kompilyasiyanın olmaması da birbaşa nəticədir. Aydındır ki, belə bir sistemə ehtiyacımız var idi, amma onun niyə mövcud olmadığı aydın deyil. Bir mühəndislə... və ya bir qrup mühəndislə problemlərim var idi. Bir vaxtlar Sunda işə başlayanda mən də... Yaxşı, təkcə o zaman yox, ümumiyyətlə, hər şeyə öz fikrim var. Və mən elə bilirdim ki, sən bu həqiqəti götürüb başa sala bilərsən. Xüsusən də çox vaxt heyrətləndirici dərəcədə haqlı olduğum üçün. Və əgər bu yanaşma xoşunuza gəlmirsə... xüsusən də açıq-aşkar səhv edirsinizsə və cəfəngiyat edirsinizsə... Ümumiyyətlə, bu ünsiyyət formasına az adam dözə bilərdi. Baxmayaraq ki, bəziləri mənim kimi edə bilər. Mən bütün həyatımı meritokratik prinsiplər üzərində qurmuşam. Mənə səhv bir şey göstərsən, dərhal dönüb deyəcəm: boş şey dedin. Eyni zamanda, təbii ki, üzr istəyirəm və bütün bunları, əgər varsa, məziyyətlərini qeyd edəcəyəm və başqa düzgün addımlar atacağam. Digər tərəfdən, ümumi vaxtın heyrətləndirici dərəcədə böyük bir faizi haqqında heyrətləndirici dərəcədə haqlıyam. Və insanlarla münasibətlərdə çox yaxşı işləmir. Mən gözəl olmağa çalışmıram, amma sualı açıq şəkildə verirəm. "Bu heç vaxt işləməyəcək, çünki bir, iki və üç." Və onlar "Oh!" Başqa nəticələr də var idi ki, onlara məhəl qoymamaq daha yaxşıdır: məsələn, həyat yoldaşımla boşanmağa və ondan sonra on illik depressiyaya səbəb olanlar.

Çağırış insanlarla, nəyi edə biləcəyinizi və ya edə bilməyəcəyinizi, nəyin vacib və nəyin olmadığını qavrayışları ilə mübarizədir. Kodlaşdırma üslubu ilə bağlı bir çox çətinliklər var idi. Mən hələ də çoxlu kod yazıram və o günlərdə hətta çoxlu paralel tapşırıqları yerinə yetirdiyim və onları birinə fokuslamaq əvəzinə zəif yerinə yetirdiyim üçün sürətimi azaltmalı oldum. Geriyə baxanda Java JIT əmri, C2 əmri üçün kodun yarısını yazdım. Növbəti ən sürətli kodlayıcı yarısını yavaş, növbəti yarısını yavaş yazdı və bu, eksponensial eniş idi. Bu sıradakı yeddinci şəxs çox, çox yavaş idi - bu həmişə olur! Çox koda toxundum. Kimin nə yazdığına baxdım, istisnasız olaraq onların koduna baxdım, hər birini nəzərdən keçirdim və yenə də onlardan daha çox özüm yazmağa davam etdim. Bu yanaşma insanlarla çox yaxşı işləmir. Bəzi insanların bu xoşuna gəlmir. Onların öhdəsindən gələ bilməyəndə isə hər cür şikayətlər başlayır. Məsələn, bir dəfə mənə kod yazmağı dayandırmağımı söylədilər, çünki çox kod yazırdım və bu, komandanı təhlükə altına alırdı və bütün bunlar mənə zarafat kimi səsləndi: dostum, əgər komandanın qalan hissəsi yoxa çıxsa və mən kod yazmağa davam etsəniz, sən Yalnız komandaların yarısını itirəcəyik. Digər tərəfdən, kodu yazmağa davam etsəm və siz komandanın yarısını itirsəniz, bu, çox pis idarəetmə kimi səslənir. Bu barədə heç vaxt düşünməmişəm, danışmamışam, amma yenə də beynimdə bir yerdə idi. Fikir beynimdə fırlanırdı: “Hamınız mənimlə zarafat edirsiniz?” Deməli, ən böyük problem mən və insanlarla münasibətlərim idi. İndi özümü daha yaxşı başa düşürəm, uzun müddət proqramçılar üçün komanda rəhbəri olmuşam və indi insanlara birbaşa deyirəm: bilirsiniz, mən kiməm və mənimlə məşğul olmaq məcburiyyətində qalacaqsınız - dayansam yaxşıdırmı? burada? Və bununla məşğul olmağa başlayanda hər şey nəticə verdi. Əslində mən nə pisəm, nə də yaxşıyam, heç bir pis niyyətim və ya eqoist istəklərim yoxdur, bu, sadəcə mənim mahiyyətimdir və birtəhər bununla yaşamalıyam.

Andrew: Bu yaxınlarda hamı introvertlər üçün özünüdərk və ümumiyyətlə yumşaq bacarıqlar haqqında danışmağa başladı. Bu barədə nə deyə bilərsiniz?

Uçurum: Bəli, həyat yoldaşımdan boşanmağımdan öyrəndiyim fikir və dərs bu idi. Boşanmadan öyrəndiklərim özümü anlamaq oldu. Başqalarını belə başa düşməyə başladım. Bu qarşılıqlı əlaqənin necə işlədiyini anlayın. Bu, bir-birinin ardınca kəşflərə səbəb oldu. Mənim kim olduğum və nəyi təmsil etdiyim barədə məlumat var idi. Mən nə edirəm: ya işimlə məşğulam, ya da münaqişədən qaçıram, ya da başqa bir şey - və bu özünüdərketmə səviyyəsi həqiqətən özümü nəzarətdə saxlamağa kömək edir. Bundan sonra hər şey çox asanlaşır. Tək özümdə deyil, digər proqramçılarda da kəşf etdiyim bir şey, emosional stress altında olanda fikirləri şifahi şəkildə ifadə edə bilməməyimdir. Məsələn, sən orada oturub kodlaşırsan, axın vəziyyətindəsən, sonra onlar qaçaraq sənin yanına gəlir və isterika ilə qışqırmağa başlayırlar ki, nəsə pozulub və indi sizə qarşı həddindən artıq tədbirlər görüləcək. Və emosional stress vəziyyətində olduğunuz üçün bir söz deyə bilməzsiniz. Əldə edilmiş biliklər sizə bu an hazırlaşmaq, sağ qalmaq və geri çəkilmə planına keçməyə imkan verir, bundan sonra nəsə edə bilərsiniz. Beləliklə, bəli, hər şeyin necə işlədiyini dərk etməyə başlayanda, bu, həyatı dəyişən böyük bir hadisədir. 
Mən özüm düzgün söz tapa bilmədim, amma hərəkətlərin ardıcıllığını xatırladım. Məsələ burasındadır ki, bu reaksiya şifahi olduğu qədər də fizikidir və sizə boşluq lazımdır. Zen mənasında belə bir məkan. Məhz bunu izah etmək lazımdır, sonra dərhal kənara çəkilin - sırf fiziki olaraq uzaqlaşın. Mən şifahi olaraq susduğum zaman vəziyyəti emosional olaraq idarə edə bilirəm. Adrenalin beyninizə çatdıqda, sizi döyüş və ya uçuş rejiminə keçirdikdə, artıq heç nə deyə bilməzsiniz, yox - indi sən axmaqsan, qamçı mühəndisisən, layiqli cavab vermək və hətta hücumu dayandırmaq iqtidarında deyilsən və təcavüzkar azaddır. təkrar-təkrar hücum etmək. Əvvəlcə yenidən özünüz olmalı, nəzarəti bərpa etməli, “döyüş və ya uçuş” rejimindən çıxmalısınız.

Və bunun üçün bizə şifahi boşluq lazımdır. Sadəcə boş yer. Əgər ümumiyyətlə bir şey deyirsinizsə, o zaman tam olaraq bunu deyə bilərsiniz və sonra gedin və həqiqətən özünüz üçün "yer" tapın: parkda gəzintiyə çıxın, duşa girin - fərqi yoxdur. Əsas odur ki, bu vəziyyətdən müvəqqəti olaraq ayrılsın. Ən azı bir neçə saniyə söndürən kimi idarəetmə geri qayıdır, ayıq düşünməyə başlayırsan. "Yaxşı, mən bir növ axmaq deyiləm, axmaq şeylər etmirəm, mən olduqca faydalı insanam." Özünüzü inandıra bildikdən sonra növbəti mərhələyə keçməyin vaxtı gəldi: nə baş verdiyini anlamaq. Sənə hücum edildi, hücum gözləmədiyin yerdən gəldi, vicdansız, alçaq pusqu idi. Bu pisdir. Növbəti addım hücumçunun buna niyə ehtiyac duyduğunu anlamaqdır. Həqiqətən niyə? Bəlkə özü qəzəbləndiyi üçün? Niyə dəli olub? Məsələn, özünü pisləşdirdiyi və məsuliyyəti qəbul edə bilmədiyi üçün? Bütün vəziyyəti diqqətlə idarə etməyin yolu budur. Ancaq bunun üçün manevr üçün yer, şifahi məkan lazımdır. İlk addım şifahi əlaqəni kəsməkdir. Sözlərlə müzakirədən çəkinin. Ləğv et, mümkün qədər tez uzaqlaş. Əgər söhbət telefon danışığıdırsa, sadəcə telefonu qapadın - bu mənim keçmiş həyat yoldaşımla ünsiyyətdən öyrəndiyim bir bacarıqdır. Söhbət heç bir yerdə yaxşı getmirsə, sadəcə "əlvida" deyin və telefonu dayandırın. Telefonun o biri tərəfindən: "blah blah bla", siz cavab verirsiniz: "bəli, sağol!" və telefonu bağla. Siz sadəcə söhbəti bitirin. Beş dəqiqədən sonra ağıllı düşünmə qabiliyyəti sizə qayıdanda bir az soyumuşsunuz, hər şeyi, baş verənləri və bundan sonra nə olacağını düşünmək mümkün olur. Və yalnız emosiyaya görə reaksiya verməkdənsə, düşünülmüş cavab formalaşdırmağa başlayın. Mənim üçün özünüdərkdə sıçrayış məhz emosional stress zamanı danışa bilməməyim idi. Bu vəziyyətdən çıxmaq, problemlərə necə cavab vermək və kompensasiya etmək barədə düşünmək və planlaşdırmaq - danışa bilmədiyiniz halda bu düzgün addımlardır. Ən asan yol, emosional stressin özünü göstərdiyi vəziyyətdən qaçmaq və sadəcə olaraq bu stressdə iştirak etməyi dayandırmaqdır. Bundan sonra düşünə bilirsən, düşünə biləndə danışa bilirsən və s.

Yeri gəlmişkən, məhkəmədə qarşı tərəfin vəkili sizə bunu etməyə çalışır - indi bunun səbəbi aydındır. Çünki o, sizi elə bir vəziyyətə salmaq qabiliyyətinə malikdir ki, məsələn, adınızı belə tələffüz edə bilmirsiniz. Çox real mənada danışa bilməyəcəksiniz. Əgər bu başınıza gəlsə və bilsəniz ki, şifahi döyüşlərin getdiyi bir yerdə, məhkəmə kimi bir yerdə tapacaqsınız, o zaman vəkilinizlə gələ bilərsiniz. Vəkil sizin üçün ayağa qalxıb şifahi hücumu dayandıracaq və bunu tamamilə qanuni şəkildə edəcək və itirilmiş Zen məkanı sizə qayıdacaq. Məsələn, mən bir neçə dəfə ailəmə zəng etməli oldum, hakim bu barədə kifayət qədər mehriban davrandı, amma qarşı tərəfin vəkili qışqırıb üstümə qışqırdı, bir söz belə deyə bilmədim. Bu hallarda vasitəçidən istifadə mənim üçün ən yaxşı nəticə verir. Vasitəçi sizə davamlı axınla tökülən bütün bu təzyiqi dayandırır, siz lazımi Zen məkanını tapırsınız və bununla da danışmaq qabiliyyəti qayıdır. Bu bütöv bir bilik sahəsidir ki, orada öyrəniləsi çox şey, öz daxilində kəşf edilməli çox şey var və bütün bunlar müxtəlif insanlar üçün fərqli olan yüksək səviyyəli strateji qərarlara çevrilir. Bəzi insanlarda yuxarıda təsvir olunan problemlər yoxdur; adətən, peşəkar satış işçiləri olan insanlarda belə problemlər olmur. Dolanışığını sözlə təmin edən bu insanların - məşhur müğənnilər, şairlər, din xadimləri və siyasətçilər hər zaman deməyə söz tapırlar. Onların belə problemləri yoxdur, amma məndə var.

Andrew: Bu... gözlənilməz idi. Əla, biz artıq çox danışmışıq və bu müsahibəni bitirməyin vaxtıdır. Biz mütləq konfransda görüşəcəyik və bu dialoqu davam etdirə biləcəyik. Hydra-da görüşənədək!

Cliff ilə söhbətinizi 2019-11 iyul 12-cu il tarixlərində Sankt-Peterburqda keçiriləcək Hydra 2019 konfransında davam etdirə bilərsiniz. O, hesabatla gələcək "Azul Hardware Transactional Memory təcrübəsi". Biletləri əldə etmək olar rəsmi saytında.

Mənbə: www.habr.com

Добавить комментарий