5 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Her gün boyunca kullanılan terminalin hızı, çalışma verimliliğini belirler; yeni sekme açma, yazı yazma ve otomatik tamamlama sırasındaki küçük gecikmeler günde yüzlerce kez birikince verimsiz hale gelir
  • Tam yüklenmiş etkileşimli kabuk, otomatik tamamlama, sözdizimi vurgulama, otomatik öneriler, fzf ve direnv dahil olduğu halde yaklaşık 30 milisaniyede başlıyor ve yeni sekmeler anında açılacak şekilde iyileştirildi
  • En büyük sır, oh-my-zsh ya da prezto gibi framework ve eklenti yöneticileri kullanmamak; sadece 3 eklenti doğrudan git clone ile alınıp .zshrc içinde source ediliyor
  • compinit önbellekleme, tembel yükleme (lazy-loading), asenkron prompt, GPU hızlandırmalı terminal gibi yöntemlerle başlangıç, prompt ve giriş gecikmesi en aza indiriliyor
  • Optimizasyonların çoğu bir şey eklemekten çok gereksiz olanları çıkarmakla ilgili; gerçekten sık kullanılanları bilinçli biçimde ekleme disiplini asıl mesele

Neden hızlı bir terminal gerekli

  • Neredeyse tüm işler terminal içinde yapılıyor; Git, kubectl, tmux, sunuculara ssh bağlantısı gibi araçlar gün boyu kullanılıyor
  • Bu kadar sık kullanılan bir aracın hızlı olması gerekir; yeni sekme açarken, karakter girerken ve Tab ile otomatik tamamlama yaparken oluşan gecikme günde yüzlerce kez hissedilir
  • Bu küçük gecikmelerin birikmesi, bin kesikle ölüm (death by a thousand cuts) gibidir

Kabuk başlangıç hızı ölçüm sonuçları

  • Güncelleme sonucunda kabuk yaklaşık 30 milisaniyede başlıyor; ölçüm için for i in {1..5}; do /usr/bin/time zsh -i -c exit; done komutu kullanılmış
  • Otomatik tamamlama, sözdizimi vurgulama, otomatik öneriler, fzf ve direnv içeren tam etkileşimli bir kabuk, 30fps tek kareden daha kısa sürede yükleniyor
  • Ortada büyük bir optimizasyon projesi yok; bu, yıllar boyunca kabuğu sade ve hızlı tutma alışkanlığının sonucu
  • Tüm ayarlar dotfiles deposunda açık olarak paylaşılıyor

Framework yok

  • En büyük kazanç, var olmayan şeylerden geliyor; oh-my-zsh, prezto ve eklenti yöneticileri kullanılmıyor
  • oh-my-zsh içindeki yüzlerce eklenti ve temanın yalnızca yaklaşık %5’i kullanılırken, kalan %95 için gereken zaman ve hesaplama kaynağı maliyeti her kabuk açılışında ödeniyor
  • Eklenti yöneticileri bunun üstüne ek yük daha bindiriyor
  • Yalnızca tam 3 eklenti kullanılıyor ve kurulum betiği bunları bir kez git clone ile alıp ardından .zshrc içinde source ediyor
    • fzf-tab, zsh-autosuggestions, zsh-syntax-highlighting
    • Başlangıçta bağımlılık çözümü yapan bir eklenti yöneticisi yok; diskte zaten bulunan dosyaları source etmek ise pratikte neredeyse bedava

Otomatik tamamlama önbellekleme

  • compinit, tipik bir .zshrc içindeki en maliyetli işlemlerden biri; varsayılan olarak her kabuk açılışında tüm otomatik tamamlama dosyaları için güvenlik denetimi yapıyor
  • Çözüm, önbellek (.zcompdump) 24 saatten daha eskiyse yalnızca o zaman tam çalıştırma yapmak, aksi halde -C ile denetimi atlamak
    • glob niteleyicisi #qNmh-24, "var ve son 24 saat içinde değiştirilmiş" anlamına geliyor
    • Böylece tam compinit günde yalnızca bir kez çalışıyor, geri kalan zamanda önbellekli okuma kullanılıyor
    Reklam

Tembel yükleme (Lazy-loading)

  • nvm, kabuk başlangıç hızını düşüren en kötü şöhretli nedenlerden biri; başlangıçta hemen source edilirse kolayca 0,5 saniye ekleyebilir
  • Her kabukta nvm gerekli değil; yalnızca nvm yazıldığında gerekiyor, bu yüzden ilk kullanımda kendisini gerçek yükleyiciyle değiştiren bir fonksiyonla sarılıyor
    • İlk nvm çağrısı geçici sarmalayıcıyı silip gerçek nvm’yi source ediyor (--no-use ile node sürümü çözümlemesi de engelleniyor) ve sonra argümanları iletiyor
  • kubectl otomatik tamamlama da aynı yöntemle ele alınıyor; otomatik tamamlama betiğini oluşturmak için kubectl ikilisini çağırdığı için ancak gerçekten ilk kullanımdan sonra yükleniyor
  • .zshrc içine eval "$(tool init zsh)" eklemenizi söyleyen her araç, başlangıçta süreç fork edip çıktıyı değerlendirdiğinden tembel yükleme adayı
  • direnv ve fzf hızlı ve sık kullanıldıkları için anında yüklenen durumda bırakılıyor; gerçekten neyin sık kullanıldığını katı biçimde değerlendirmek gerekiyor

Bloklamayan prompt

  • git status komutunu eşzamanlı çalıştıran bir prompt, bir miktar büyük depolarda gecikme yaratır; bu da her Enter tuşuna bastığınızda hissedildiği için yavaş başlangıçtan bile daha kötü olabilir
  • pure kullanılıyor; prompt hemen render ediliyor, Git bilgisi ise hazır olduğunda asenkron biçimde dolduruluyor
  • Bir süre zsh yerleşik vcs_info ile değiştirme denemesi yapılmış ama pure’un asenkron davranışı daha iyi bulunmuş
  • İstenirse asenkron git status doğrudan prompt içine de uygulanabilir, ancak pure bunu bu kullanım için oldukça iyi soyutluyor

Terminal emülatörünün kendisi

  • Kabuk başlangıcı hikâyenin yalnızca yarısı; emülatörün kendisi de giriş gecikmesi ekler
  • GPU hızlandırmalı yerel bir terminal olan Ghostty kullanılıyor ve ayarlar sadece 7 satır
  • tmux new -A -s main takma adı (t) ile birlikte kullanıldığında yeni terminal penceresi doğrudan mevcut oturuma geri döndürüyor
Reklam

Kendi kabuk performansınızı nasıl ölçersiniz

  • Sürenin nereye harcandığını doğrudan terminalde ölçebilirsiniz; bakılması gereken üç gecikme türü başlangıç süresi, prompt gecikmesi ve giriş gecikmesi
  • Temel ölçüm için time zsh -i -c exit birkaç kez çalıştırılır; ilk çalıştırma soğuk önbellek nedeniyle her zaman daha yavaştır
    • 100 ms altı kabul edilebilir, 50 ms altı mükemmel, 500 ms üstü ise müdahale gerektirir
  • Daha doğru istatistikler için hyperfine kullanın: hyperfine --warmup 3 'zsh -i -c exit'
  • zsh içine gömülü profil aracını kullanın
    • .zshrc dosyasının en üstüne zmodload zsh/zprof, en altına zprof eklerseniz sürenin nereye gittiğini sıralı tablo halinde gösterir
    • En üst kalemler genelde compinit, nvm.sh dosyasını source etme ve eval "$(...)" olur; en üsttekinden başlayıp düzeltme yaparak tekrar çalıştırın
    • İşiniz bitince bu iki satırı kaldırın
  • zprof yetmezse tüm başlangıcı zaman damgalarıyla izleyin: zsh -ixc exit 2>&1 | ts -i '%.s' | sort -rn | head -20
    • Ya da PS4='+%D{%s.%6.}: ' ayarlayıp zsh -ixc exit 2> startup.log çalıştırın, sonra satırlar arasındaki büyük sıçramalara bakın
  • Başlangıç hızlı olsa bile prompt yeniden çizimi yavaş olabilir; en büyük Git deponuza cd yaptıktan sonra Enter’a basın, bir sonraki prompt görünmeden önce gecikme varsa prompt eşzamanlı iş yapıyordur
    • Asenkron prompt’a geçebilir veya Git özelliklerini kaldırabilirsiniz

Sonuç

  • Optimizasyonların çoğu bir şeyleri çıkarmakla ilgilidir; bilinçli davranmak ve yalnızca gerçekten kullanacaklarınızı eklemek temel noktadır
  • Böyle yapıldığında gün içinde açılan onlarca oturumun hepsi anında açılır ve terminal, beklenmesi gereken bir uygulama değil zihnin bir uzantısı gibi hissettiren bir araç haline gelir
  • Gün boyu kullanılan bir araç için bu hız taviz verilemez
  • Yukarıdaki tüm ayarlar dotfiles deposunda açık olarak paylaşılmış durumda

1 yorum

 
GN⁺ 4 시간 전
Lobste.rs görüşleri
  • Teknik olarak çoğu durumda kastedilen şey terminal değil, shell

  • Varsayılanları düzgün olan araçları kullanmak daha iyi; bu yüzden fish kullanmak yeterli

    • İş yerindeki ZSH yaklaşık bir yıldır saçma derecede yavaşladı, ben de fish denedim ve yaşam kalitesini artıran özelliklerini gerçekten beğendim
      Ok tuşlarıyla seçilebilen modern sekme tamamlama gibi özelliklerin varsayılan gelmesi güzeldi; kişisel cihazlarımda hâlâ ZSH kullanıyorum ama bunun tek nedeni Nix ayarlarımı ve home manager yapılandırmamı elden geçirecek zaman bulamamış olmam
    • Keşke biri bash uyumlu bir fish yapsa
      Mantıklı varsayılanları ve hızlı yerleşik tamamlaması olan, ama bash tabanlı araçları terk etmeyi ya da yeniden yazmayı gerektirmeyen bir shell güzel olurdu
    • Yeni araçlar kurmak için hayat çok kısa; sadece mantıklı varsayılanlar yeter
  • Bazen engellemeyen prompt ya da OpenGL tabanlı terminaller gibi şeylerin, xterm’de sadece PS1="\W: " kullanmaya kıyasla gerçekten buna değip değmediğini merak ediyorum

    • Yıllardır bilerek xterm kullanmıyordum ama çeşitli terminal emülatörlerine bakınca xterm’in OpenType yazı tiplerini, UTF-8’i, çoğu emojiyi, 24 bit rengi ve düşük bellek kullanımını desteklediğini görmek beni epey şaşırttı
      Üstelik çok hızlı ve “standart” olma avantajına sahip; bu yüzden kalan hatalar da genelde önemsiz oluyor ya da içinde çalışan programların normal davranış kabul etme ihtimali yüksek oluyor
      Bu yüzden tekrar xterm kullanmaya başladım
    • O kadar da değmiyor
      zsh başlangıcı aslında çok hızlıdır; yavaşlaması ancak kullanıcı onu yavaşlattığında olur
      Anlamadığınız bir sürü şeyi içine doldurmamak yeterli; buna, kendine “minimal” deyip her prompt oluşturulduğunda yüzlerce komut çalıştıran kütüphaneler de dahil
      Benim zsh yapılandırmam 90’lardan beri çok yavaş şekilde evrilen birkaç yüz satırlık bir dosya; her satırını anlıyorum ve neden orada olduğunu biliyorum
      Özellikle hızlı olsun diye hiç uğraşmadım ama yine de 20ms’de başlıyor; yavaşlatabilecek aptalca bir değişiklik yaparsam da hemen fark edip düzeltebiliyorum
  • time zsh -i -c exit gibi bozuk benchmarkların hâlâ yaygın kullanılmasından hoşlanmıyorum
    Tamamen yanlış şeyi ölçüyorlar ve bazı zsh eklenti yöneticileri, gerçek shell başlangıç gecikmesini feda etme pahasına bu işe yaramaz metriğe göre optimize edildi
    zsh-bench içinde bu benchmark’ın neden anlamsız olduğunu açıklayan bir bölüm var: https://github.com/romkatv/zsh-bench#how-not-to-benchmark
    zsh-bench’in ölçtüğü ilk prompt gecikmesi ya da giriş gecikmesi gibi metrikler çok daha faydalı

  • Bunun GPU hızlandırmalı terminal hatalarıyla ilgili olacağını sanmıştım; öyle çıkmamasına sevindim
    Tamamlama önbellekleme iyi bir ipucu ve iş için kullandığım Mac’te zsh çalıştırıyorum; yeni sekme açmayı düşününce bile beachball çıktığı için umarım işe yarar
    kubectl tamamlama için yavaş olan kısmın tamamlama üretimi mi yoksa yüklenmesi mi olduğunu merak ediyorum; eğer ilkiyse dosyaya kaydedip sonra okumak başlangıç süresini azaltır mı diye de merak ediyorum
    jj için bunu yapıyorum ve jjye geçince prompt’tan git status çalıştırmayı da çıkardım
    Keşke yazar kendi sürelerini de gösterseydi; o zaman benim 0.287 saniyemin ortalama mı yoksa yavaş mı olduğunu anlayabilirdim
    Sonra ölçtüm: neredeyse boş .bashrc 0.007 saniye, skim tuş bağları sonrası 0.043 saniye, mise sonrası 0.115 saniye, jj tamamlama sonrası 0.186 saniye, /etc/bashrc de okununca 0.294 saniye; yani iyileştirme alanı var gibi görünüyor

    • Yazıda shell’in kendisinin ön tarafta 30ms olduğu söyleniyordu; aynı time shell -c exit testinde benimki yaklaşık 50ms çıkıyor
      Başka insanların Linux ortamlarını kullanırken beni en çok sinirlendiren şey her yerdeki gereksiz animasyonlar
      Kendi bilgisayarımda kısayola bastığım anda terminal penceresi neredeyse anında açılıyor; bazen pencere ile prompt arasında sadece kısa bir yanıp sönme görüyorum
      Bu yüzden yeni pencere açıp shell içinde bir şey yapıp kapatmayı içeren uçtan uca test önemli; time myterm deyip pencerede Ctrl+D ile kapattığımda sonuç hep 0.120 saniyenin altındaydı
      Gereksiz animasyon ve compositing’i kaldırınca yapılabilecek çok şey oluyor; iki elektronik tablo arasındaki farklara bakarken de iki pencereyi büyütüp pencere sarma kısayoluyla hızla aralarında geçince farklar anında görünüyordu
      Windows’ta aynı şeyi Excel animasyonları eşliğinde yapmak fazla dikkat dağıtıcı
    • 100ms altı benim ortamımda zor görünüyor
      Boş ayarlarla bile zsh -i -c exit ortalaması 129.8ms ve tam yapılandırma da benzer şekilde yaklaşık 250ms sürüyor
      compinit önbelleklemesiyle ortalamada yaklaşık 5ms kazandım ama tamamlamalar eksik kalabildiği için verilen emeğe pek değdiğini düşünmüyorum
  • Son zamanlarda zsh başlangıcı neredeyse donmuş gibi yavaşlamıştı; kesin sebebi bulamadım ama kritik yolun büyük kısmını compinit’in kapladığını doğruladım
    Yazıda önerilen yönteme çok benzer şekilde önbellekleme uygulayarak yavaşlamayı giderdim; ayrıca o havalı glob qualifier’ı görünce kendi yöntemimi de iyileştirmem gerektiğini düşündüm
    Böyle bir şeyin mümkün olduğunu bilmiyordum; açıkçası biraz şüpheli bir özellik gibi görünüyor ama yine de kullanacağım
    Daha önce hedef yolu oluştururken nispeten kaba bir date -Id yaklaşımı kullanıyordum
    zsh gibi tam teşekküllü bir programlama diliyle yapılandırılan araçları seviyorum; böylece yazarın önbellekleme özelliği eklemesini beklemeden bunu kendiniz uygulayabiliyorsunuz
    Yaklaşık 20 yıldır zsh kullanıyorum; hiç framework ya da eklenti yöneticisi kullanmadım ve bunlar daha çok stil amaçlı kullanılıyor gibi görünüyor
    Ben bilişim ortamımın estetiğine önem vermediğim için şanslıyım; kendi yazdığım prompt da basit, küçük ve bilgilendirici ama hiç gösterişli değil ve siyah arka planlı varsayılan terminal temasını kullanıyorum

    • compinit önbellekleme önbelleğin bayat kalabilmesi yüzünden can sıkıcı
      Birden fazla shell örneği paralel olarak aynı işi yapabiliyor; tmux içinde deneme amaçlı paralel örnekler açarken bunu sık yaşadım
      Ayrıca birden fazla host, özellikle de container’lar arasında home dizinini paylaşıyor olabilirsiniz; bu yüzden sonunda kilit dosyaları, son kullanma kontrolü ve zcompile koşul işlemesini de içeren bir yöntemle toparladım
    • ZSH yükleme süresi o kadar kötüleşti ki doğrudan fish denedim
      Ne yazık ki fish yapılandırması da yavaş yavaş aynı yöne kaymış gibi görünüyor; pazartesi günü boş vaktimde profilleme yapıp lazy loading tekniklerinin gerçekten benim durumda işe yarayıp yaramadığını göreceğim
      Yavaşlamanın büyük kısmı muhtemelen Starship’in git modülünden geliyor ama lazy load edilebilecek epey alias ve yardımcı fonksiyon da var
  • Emacs’te uzun zamandır arka planda hazır bekleyen shell önceden başlatılıyor
    Terminal açmak demek o buffer için yeni bir pencere açıp yeniden ad vermek; ardından bir sonraki kullanım için shell’i tekrar hazırlayan bir thread fork ediliyor
    Bu yüzden başlangıç gecikmesi yok
    Eskiden reptyr ile Emacs dışı bir çözümü de zorlamaya çalıştığımı hatırlıyorum ama sonunda onu kullanmaya devam etmedim; nedenini de pek hatırlamıyorum
    https://github.com/nelhage/reptyr

    • Android’deki zygote process gibi hissettirmesi hoş
  • Benzer şekilde kurcalarken zsh-abbrın başlangıç süresinden yaklaşık 100ms yediğini fark ettim ama o kadar sorun değil
    Oradan buradan 10ms azaltılabilir ama kaybedilen işlevi düşününce buna değmiyor gibi geliyor
    Yaklaşık 300ms başlangıç süresiyle yaşamaya razıyım; yeterince hızlı ve zaten ardı ardına terminal açıp anında yazı yazmam gereken durumlar pek olmuyor
    Yine de yazı güzeldi; hyperfineı öğrenmiş oldum ve birkaç zsh başlangıç dosyasına dönüp baktım

  • Sayesinde uzun süredir ertelediğim zshrc düzenlemesini yaptım; şimdi 80ms’ye düştü ve harika oldu

  • Benim hayatım yavaş terminalleri kaldıracak kadar uzun ve bazen terminalin daha da yavaş olmasını diliyorum
    Mesela root konsolunda gerçekten çalıştırmadan önce varsayılan 5 saniyelik gecikme olsaydı ve bu sayede yazım hatasını Ctrl+C ile iptal etme fırsatı verseydi, asi gençlik yıllarımda birkaç gün kurtarabilirdim