Bölüm 14:Sistemi Gözlemlemek
CPU'ya “Sen”i Katmak yazısının parçası: bilgisayarının programları nasıl çalıştırdığına doğru inen uzun bir teknik tavşan deliği.
Tüm bölümler
- Giriş
- Başlamadan Önce
- Temeller
- Bellek Hiyerarşisi
- Zamanı Dilimle
- Modern İşlemci Teknikleri
- Bir Program Nasıl Çalıştırılır?
- Shell'den Kernel'e
- Bir ELF Ustasına Dönüşmek
- Bilgisayarındaki Çevirmen
- Bellek Güvenliği ve Sertleştirme
- Container ve İzolasyon
- Fork'lar ve COW'lar Hakkında Konuşalım
- Dosya Sistemi ve I/O
- Sistemi Gözlemlemek
- Son Söz
Şimdiye kadar okuduğun her şey — syscall’lar, sayfa hataları, context switch’ler, dinamik bağlama — soyut kavramlar değil. Hepsi şu anda makinende olup bitiyor ve hepsini doğrudan ölçebilirsin.
Bu bölüm yeni bir kavram öğretmiyor. Öğrendiklerini görünür kılan araçları tanıtıyor; çünkü bir mekanizmayı gerçekten anladığını, onu kendi sisteminde gösterebildiğinde anlarsın.
Bu bölümde neyi çözüyoruz?
- Bir programın yaptığı syscall’ları
straceile canlı izleyeceğiz./procüzerinden çalışan bir process’in bellek haritasını ve durumunu okuyacağız.perfile cache miss ve branch miss sayaçlarını ölçüp 3. ve 5. bölümdeki iddiaları doğrulayacağız.
strace: Kernel’a Yapılan Her Çağrı#
2. bölümde syscall’ın user mode ile kernel mode arasındaki resmi kapı olduğunu görmüştük. strace bu kapıdan geçen her şeyi yazdırır.
En basit programla başlayalım:
strace -f echo merhabaÇıktı uzun görünür ama tanıdıktır. Başta execve vardır — 6. bölümde gördüğümüz, programı belleğe yükleyen çağrı. Ardından dinamik bağlayıcının kütüphane arayışı gelir: openat, mmap, fstat. Sonunda tek bir write ve exit_group.
Gürültüyü azaltıp yalnızca ilgilendiğin çağrılara bakabilirsin:
strace -e trace=openat,read,write -f cat /etc/hostnameHangi çağrıların ne kadar sürdüğünü özetlemek için:
strace -c ls /usr/binBu tablo, “program neden yavaş” sorusuna çoğu zaman ilk cevabı verir. Binlerce stat çağrısı görüyorsan sorun disk erişim desenindedir; futex çağrıları tepedeyse thread’ler kilit için bekliyordur.
Bir yana: strace neden programı yavaşlatır?
strace,ptracesyscall’ı üzerinden çalışır ve izlenen her çağrıda process’i durdurup izleyiciye kontrolü verir. Yani her syscall iki ek context switch demektir. Yoğun I/O yapan bir programıstracealtında çalıştırmak onu kat kat yavaşlatabilir; ölçüm yaparken bunu hesaba kat. Üretimdeki bir process’e bağlanacaksan-p PIDile bağlanabilirsin, ama aynı yavaşlama orada da geçerlidir.
ltrace ise aynı işi kütüphane çağrıları için yapar: malloc, strcpy, printf gibi libc fonksiyonlarını gösterir. 8. bölümde gördüğümüz PLT mekanizmasını çalışırken izlemenin en kolay yoludur.
/proc: Kernel’ın Açık Defteri#
Bir önceki bölümde /proc’un diskte karşılığı olmayan sanal bir dosya sistemi olduğunu gördük. Çalışan her process için orada bir dizin vardır ve içi, o process hakkında kernel’ın bildiği her şeydir.
Kendi kabuğunun bellek haritasına bakalım:
cat /proc/self/mapsHer satır bir bellek bölgesidir: adres aralığı, izinler, dosya eşlemesi. 9. bölümde anlatılan her şey burada somut hâlde durur — r-xp kod bölgeleri, rw-p veri bölgeleri, [heap], [stack] ve eşlenmiş kütüphaneler.
Bellek kullanımının ayrıntılı dökümü için:
grep -E 'VmRSS|VmSize|Threads' /proc/self/statusVmSize process’in sanal adres alanı, VmRSS ise gerçekten RAM’de duran kısımdır. İkisi arasındaki fark genelde büyüktür ve bu tuhaf değildir: demand paging sayesinde eşlenmiş ama hiç dokunulmamış sayfalar fiziksel bellek tüketmez. Bir programın “8 GB bellek kullanıyor” görünüp aslında 200 MB tutmasının açıklaması budur.
Sayfa hatası sayaçlarını da doğrudan okuyabilirsin:
ps -o min_flt,maj_flt,cmd -p $$min_flt (minor fault) sayfanın zaten bellekte olduğu, yalnızca eşlemenin kurulması gereken durumdur — ucuzdur. maj_flt (major fault) ise diske gidilmesi gerektiği anlamına gelir ve pahalıdır. Sağlıklı bir sistemde major fault sayısı düşük kalır; sürekli artıyorsa makine bellek baskısı altındadır.
perf: Donanım Sayaçlarını Oku#
strace kernel’a yapılan çağrıları gösterir, ama CPU’nun içinde ne olduğunu söylemez. perf tam olarak orayı ölçer; modern işlemcilerdeki performans sayaçlarını okur.
3. bölümde satır bazlı ve sütun bazlı matris erişiminin cache davranışı yüzünden farklı hızlarda çalıştığını söylemiştik. Bunu artık iddia olarak bırakmak zorunda değiliz:
#include <stdlib.h>
#define N 4096
int main(int argc, char **argv) {
static int m[N][N];
long sum = 0;
if (argc > 1) { // sütun bazlı: her erişim yeni cache line
for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)
sum += m[i][j];
} else { // satır bazlı: ardışık erişim
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
sum += m[i][j];
}
return sum == 0;
}Derleyip iki varyantı ölç:
gcc -O1 -o cache-testi cache-testi.c
perf stat -e cache-misses,cache-references,instructions ./cache-testi
perf stat -e cache-misses,cache-references,instructions ./cache-testi sutunİki çalıştırma neredeyse aynı sayıda talimat yürütür, ama sütun bazlı sürümün cache miss sayısı kat kat yüksektir ve geçen süre buna paralel artar. Aynı işi yapan iki döngü arasındaki farkın tamamı bellek erişim deseninden gelir.
Aynı araçla 5. bölümdeki branch prediction iddiasını da sınayabilirsin:
perf stat -e branches,branch-misses ./programSıralanmış bir dizide dallanma tahmin edilebilir olduğu için branch-miss oranı düşer; aynı veri karıştırıldığında oran yükselir ve program yavaşlar.
Zamanın nerede harcandığını fonksiyon düzeyinde görmek için:
perf record -g ./program
perf reportİzin gerekebilir.
perfçekirdek sayaçlarına eriştiği için çoğu dağıtımda/proc/sys/kernel/perf_event_paranoiddeğeri erişimi kısıtlar. Kendi makinende geçici olarak gevşetebilirsin, ama paylaşılan bir sunucuda bu ayarı değiştirmeden önce iki kez düşün: sayaçlar yan kanal ölçümü için de kullanılabilir.
ftrace ve eBPF: Kernel’ın İçine Bakmak#
strace kernel’ın kapısındaki trafiği, perf CPU sayaçlarını gösterir. Peki kernel’ın içinde hangi fonksiyonun çağrıldığını görmek istersen?
ftrace, kernel’a gömülü izleme altyapısıdır ve /sys/kernel/debug/tracing altından yönetilir. Ham kullanımı zahmetlidir; trace-cmd gibi sarmalayıcılar işi kolaylaştırır.
eBPF ise bugünün cevabı. Kernel içinde çalışan küçük, doğrulanmış programlar yazmanı sağlar: bir kernel fonksiyonuna bağlanır, olay gerçekleştiğinde veri toplar. Kernel’ı yeniden derlemeye veya modül yüklemeye gerek yoktur ve doğrulayıcı, programın sonsuz döngüye girmesini veya geçersiz belleğe erişmesini baştan engeller.
bcc ve bpftrace araç setleri bunu kullanılabilir kılar:
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @[comm] = count(); }'Bu tek satır, sistemdeki hangi programın kaç kez dosya açtığını canlı sayar. Ctrl-C ile durdurduğunda özet tabloyu verir. Aynı yaklaşımla disk gecikmelerini, TCP yeniden iletimlerini veya scheduler kuyruk sürelerini ölçebilirsin — üstelik üretim yükü altında, strace’in getirdiği ağır bedel olmadan.
Pratik: Yavaş Bir Programı Teşhis Etmek#
Araçları tek tek bilmek yetmiyor; hangi soruyu hangi araca soracağını bilmek gerekiyor. Kaba bir karar sırası:
- Program CPU’da mı bekliyor, yoksa bir şey mi bekliyor?
topya datime. Gerçek süre (real) CPU süresinden (user + sys) çok büyükse program bekliyordur. - Bekliyorsa neyi bekliyor?
strace -cile hangi syscall’da zaman geçtiğine bak.read/futexağırlıklıysa I/O ya da kilit sorunu vardır. - CPU’da yanıyorsa nerede?
perf recordile profil çıkar,perf reportile sıcak fonksiyonu bul. - Sıcak fonksiyon beklenenden yavaşsa neden?
perf statile cache-miss ve branch-miss oranlarına bak; bellek erişim deseni mi, dallanma mı sorun? - Bellek büyüyor mu?
/proc/PID/statusiçindekiVmRSSdeğerini zaman içinde izle.
Bu sıralama, tahmin etmek yerine ölçmeye zorlar. Performans işinde en pahalı hata, yanlış yeri optimize etmektir.
Özet#
stracesyscall’ları,ltracekütüphane çağrılarını gösterir; ikisi deptraceüzerinden çalıştığı için ölçülen programı yavaşlatır./proc/PID/mapssanal bellek yerleşimini,statusRSS ve thread sayısını,min_flt/maj_fltsayfa hatalarını verir.perf statdonanım sayaçlarıyla cache ve branch davranışını ölçer;perf recordzamanın hangi fonksiyonda geçtiğini gösterir.- eBPF, kernel içinde güvenli gözlem yapmayı mümkün kılar ve üretim ortamında
strace’e göre çok daha ucuzdur. - Teşhiste sıra önemlidir: önce bekliyor mu diye bak, sonra neyi beklediğini bul, en son mikro-optimizasyona in.
Bu bölümle birlikte teoriyi ölçmeye çevirdik. Son bölümde geriye dönüp bakacağız: parçaları birleştirdiğimizde bilgisayarın bir programı çalıştırma hikâyesi baştan sona nasıl görünüyor?
15. bölüme devam et: Son Söz