tiptop ile CPU Performans Sayaçlarını (PMU) Süreç Bazında İzleme
Performans sorunlarını debug etmenin en can sıkıcı yanı şu: top açıyorsun, bir sürecin CPU’yu %80 yuttuğunu görüyorsun, ama neden yuttuğunu göremiyorsun. İşte tam bu noktada donanım düzeyindeki performans sayaçlarına ihtiyaç duyuyorsun. tiptop tam da bu iş için var: Linux’un PMU (Performance Monitoring Unit) altyapısını kullanarak süreç bazında cache miss, instruction retired, branch misprediction gibi düşük seviyeli metrikleri gerçek zamanlı gösteriyor.
tiptop Nedir, Ne Değildir?
tiptop, perf stat ile top‘un birleşimi gibi düşünebilirsiniz. perf stat size harika veriler verir ama tek seferlik snapshot alır ve çalışan bir süreci izlemek için pek elverişli değildir. top ise sürekli güncellenir ama donanım sayaçlarından haberi yoktur. tiptop bu ikisinin ortasında durur: top gibi arayüzü vardır, perf gibi PMU verisi üretir.
Mimarisi itibariyle Linux’un perf_event_open() sistem çağrısını kullanır. Yani kernel düzeyinde desteklenen her metriği okuyabilir. Intel VTune ya da AMD uProf gibi ağır araçlara gerek duymadan, terminal üzerinden doğrudan işlemcinin sayaç registerlarına erişirsiniz.
Bir uyarı vereyim hemen: tiptop çok popüler bir araç değil. Paket repolarında bulunabilir ama güncellemeler seyrek gelir. Bu yüzden bazı modern kernel versiyonlarıyla küçük uyumsuzluklar çıkabiliyor. Buna rağmen, alternatifi yok denecek kadar az olduğu için öğrenmeye değer.
Kurulum
Debian/Ubuntu tabanlı sistemlerde:
sudo apt-get install tiptop
RHEL/CentOS/Rocky Linux’ta paket repolarında olmayabilir, kaynaktan derlemeniz gerekebilir:
sudo yum install -y gcc libpfm-devel libxml2-devel ncurses-devel
git clone https://github.com/nsc-grp/tiptop.git
cd tiptop
./configure
make
sudo make install
Kurulumu doğrulamak için:
tiptop --version
Eğer perf_event_open ile ilgili izin hatası alırsanız, kernel parametresine bakmak gerekir:
cat /proc/sys/kernel/perf_event_paranoid
Bu değer 2 ya da üzerindeyse tiptop düzgün çalışmaz. Değeri düşürün:
sudo sysctl -w kernel.perf_event_paranoid=1
Kalıcı yapmak için /etc/sysctl.conf dosyasına ekleyin. Güvenlik açısından bu değerin production sistemlerde ne anlama geldiğini bilmek gerekir: 1 demek, root olmayan kullanıcıların da kernel ve userspace sayaçlarını okuyabileceği anlamına gelir. Sadece kendi makinenizde ya da izole test ortamında yapmanızı öneririm.
Temel Kullanım ve Arayüz
En basit haliyle root ya da uygun izinlerle çalıştırıyorsunuz:
sudo tiptop
Karşınıza top‘a benzeyen bir arayüz çıkacak. Farkı, sağ tarafa uzayan kolonlar: %CPU, P (işlemci no), Mcycle, Minstr, IPC, %BMIS, %L1MISS, %LLMISS gibi alanlar görürsünüz.
Bu kolonların ne anlama geldiğini bir kez anlamak, sonrasındaki her şeyi kolaylaştırıyor:
- Mcycle: Milyon CPU cycle sayısı. Sürecin ne kadar “iş” yaptığının ham göstergesi.
- Minstr: Retire edilen milyon instruction sayısı. Cycle’dan farklı olarak gerçekten tamamlanan iş.
- IPC: Instructions Per Cycle. 1’in altındaysa süreç memory bound, 3-4 civarındaysa compute bound ve iyi optimize edilmiş demektir.
- %BMIS: Branch misprediction oranı. Yüksekse algoritmanızda öngörülemeyen dallanmalar var demektir.
- %L1MISS: L1 cache miss oranı. Veri erişim patternleriniz cache-friendly değil demektir.
- %LLMISS: Last Level Cache (genellikle L3) miss oranı. Bu yüksekse süreç sık sık main memory’e gidiyor, çok pahalı.
Belirli Bir Süreci İzlemek
Sistem genelinde izlemek yerine belirli bir PID’i hedefleyebilirsiniz:
sudo tiptop -p 12345
Ya da bir komut çalıştırarak onun metriklerini izleyebilirsiniz:
sudo tiptop -- stress --cpu 4
Bu ikinci form çok kullanışlı: test workload’larıyla benchmark yaparken anlık davranışı görmek için idealdir. Örneğin bir web sunucusunun bir istek işleme döngüsünü izlemek istiyorsanız, o süreci başlatıp hemen arkasına bu komutu koyabilirsiniz.
Thread bazında da izleyebilirsiniz. Çok thread’li uygulamalarda hangi thread’in sorun çıkardığını bulmak için:
sudo tiptop -K
-K flag’i kernel thread’lerini de gösterir. Eğer userspace thread’lerini ayrı ayrı görmek istiyorsanız -t flag’ini kullanın:
sudo tiptop -t -p 12345
Gerçek Dünya Senaryosu: Java Uygulamasında GC Sorununu Tespit Etmek
Bir e-ticaret şirketinin backend ekibinde çalıştığımı düşünün. Üretim ortamında çalışan bir Java mikro servis, zaman zaman latency spike yaşıyordu. top‘a baktığımızda CPU kullanımının %70-80 arasında gezindiğini görüyorduk ama bu single core’da mı oluyor, birden fazla core’da mı paralel mi çalışıyor, net değildi.
tiptop ile süreci izlemeye başladık:
sudo tiptop -p $(pgrep -f "java.*myservice") -d 2
-d 2 parametresi güncelleme aralığını 2 saniyeye çeker. Spike sırasında IPC değerinin 0.3-0.4’e düştüğünü gördük. Normal çalışmada bu değer 1.8-2.1 civarındaydı. Aynı anda %LLMISS değeri %35’e çıkıyordu.
Bu kombinasyon bize şunu söyledi: GC devreye girdiğinde heap’teki nesneleri taramak için hafızanın rastgele bölgelerine erişiyor, bu erişimler cache-friendly değil çünkü GC’nin ne zaman hangi nesneye bakacağı tahmin edilemez. Sonuç: yüksek LLC miss, düşük IPC, latency spike.
JVM parametrelerini G1GC’den ZGC’ye geçirince bu sayaç değerleri anlamlı ölçüde düzeldi. GC-induced latency’yi tiptop olmadan tespit etmek çok daha uzun sürerdi.
Özel Sayaç Konfigürasyonu
tiptop‘un varsayılan gösterdiği sayaçlar değiştirilebilir. Konfigürasyon dosyası /etc/tiptop.conf ya da ~/.tiptoprc konumunda olabilir. Olmadığı durumda -w flag’iyle özel bir screen tanımlayabilirsiniz.
Aşağıdaki örnek, TLB miss ve memory bandwidth’e odaklanan bir izleme görünümü oluşturur:
sudo tiptop -w "dtlb_misses.miss_causes_a_walk / instructions * 100"
-w "mem_uops_retired.all_loads / cycles"
Bu sözdizimi biraz farklı görünebilir. tiptop XML tabanlı bir konfigürasyon dosyası da destekler. Örnek bir konfigürasyon:
cat ~/.tiptoprc
<?xml version="1.0"?>
<tiptop>
<screen name="memory" desc="Memory access patterns">
<counter alias="DTLB_MISS" config="dtlb_load_misses:miss_causes_a_walk" />
<counter alias="LLC_MISS" config="LLC-load-misses" />
<column header=" DTLB%"
formula="DTLB_MISS / INSTR * 100"
format="%6.2f" />
<column header=" LLC%"
formula="LLC_MISS / INSTR * 100"
format="%6.2f" />
</screen>
</tiptop>
Bu konfigürasyonla özelleştirilmiş ekranı yükleyebilirsiniz:
sudo tiptop --config ~/.tiptoprc
Konfigürasyon dosyasını bir kez doğru kurduğunuzda, her seferinde aynı parametrelerle başlatmak zorunda kalmazsınız. Özellikle birden fazla ekip üyesiyle çalışıyorsanız, bu dosyayı git repo’ya koyup ortak bir izleme standardı oluşturabilirsiniz.
Gerçek Dünya Senaryosu: Nginx Worker’larında Cache Thrashing
Bir CDN altyapısını yönettiğinizi hayal edin. Nginx ile statik dosya sunuyorsunuz ve beklenmedik bir şekilde throughput düşüşü yaşıyorsunuz. sar, vmstat ve iostat normal görünüyor. CPU kullanımı makul ama response time yüksek.
Nginx worker process’lerini tiptop ile izleyelim:
sudo tiptop -t -p $(cat /var/run/nginx.pid) -d 1
Nginx master değil worker thread’lerine bakıyoruz. Eğer worker sayısı CPU sayısıyla eşleşmiyorsa burada ilk ip ucunu alırsınız. Ama asıl ilginç olan şu: bazı worker’ların %L1MISS değeri diğerlerinden 3-4 kat yüksekti.
Bu durum genellikle NUMA topology’siyle ilgilidir. Farklı NUMA node’larındaki worker’lar, başka node’un memory’sine erişmek zorunda kaldıklarında cache miss oranları artar. Çözüm için:
numactl --hardware
Çıktıya bakarak kaç NUMA node’unuz olduğunu görün. Ardından Nginx worker’larını NUMA node’larına pin’leyin:
numactl --cpunodebind=0 --membind=0 nginx -g "worker_processes 4;"
Sonrasında tiptop ile tekrar izlediğinizde cache miss oranlarının dengelendiğini görürsünüz.
Batch Mod ve Script Entegrasyonu
tiptop sadece interaktif kullanım için değil, script’lere entegre edebilirsiniz. Batch modda çalıştırmak için:
sudo tiptop -b -d 5 -n 12 > /tmp/tiptop_output.txt
- -b: Batch mod, terminal kontrolü kapatılır, çıktı pipe/dosyaya yönlendirilebilir
- -d 5: 5 saniyede bir güncelle
- -n 12: 12 iterasyon sonra dur (yani 60 saniye izle)
Bu çıktıyı parse ederek kendi monitoring sistemlerinize entegre edebilirsiniz. Örneğin belirli bir sürecin IPC değeri belirli bir eşiğin altına düştüğünde alert gönderen basit bir script:
#!/bin/bash
PID=$1
THRESHOLD=0.5
ALERT_EMAIL="[email protected]"
sudo tiptop -b -d 10 -n 6 -p $PID | grep -E "^s+$PID" | while read line; do
IPC=$(echo $line | awk '{print $8}')
if (( $(echo "$IPC < $THRESHOLD" | bc -l) )); then
echo "UYARI: PID $PID icin IPC degeri $IPC - esik: $THRESHOLD" |
mail -s "Performans Uyarisi" $ALERT_EMAIL
fi
done
Bu yaklaşım production’da çok güçlü: normal monitoring araçları CPU kullanımını gösterir ama “bu CPU kullanımı verimli mi?” sorusunu yanıtlayamaz. tiptop bunu yanıtlayabilir.
IPC Değerlerini Yorumlamak
IPC değerleri yorumlanabilmesi için bağlam gerektirir. Genel bir rehber:
- IPC < 0.5: Ciddi memory bottleneck ya da I/O wait. Süreç CPU’da çalışıyor gibi görünse de aslında veri bekliyor.
- IPC 0.5 – 1.0: Memory bound ama tolere edilebilir seviye. Veri locality’sini iyileştirmek fayda sağlar.
- IPC 1.0 – 2.0: Dengeli çalışma. Çoğu gerçek dünya uygulaması bu aralıkta.
- IPC 2.0 – 4.0: Compute bound, iyi optimize edilmiş kod. Numerik hesaplama, sıkıştırma, şifreleme işlemleri bu aralıkta olabilir.
- IPC > 4.0: Genellikle SIMD (vektörel) instruction’ların yoğun kullanıldığı durumlarda görülür.
Modern Intel işlemcilerde teorik maksimum IPC değeri mimariye göre 4-6 arasında değişir. AMD Zen mimarisinde de benzer değerler geçerlidir. Bu değerlere yaklaşmak için hem algoritma hem de veri yapısı optimizasyonu gerekir.
perf ile Karşılaştırmalı Kullanım
tiptop her şeyin çözümü değil. Bazı durumlarda perf ile birlikte kullanmak daha anlamlı sonuçlar verir. Şöyle bir workflow öneririm:
Önce tiptop ile anomaliyi tespit edin:
sudo tiptop -p $(pgrep myapp) -d 1
Yüksek %LLMISS gördünüz diyelim. Ardından perf ile detaylı profiling yapın:
sudo perf stat -p $(pgrep myapp) -e cache-misses,cache-references,LLC-loads,LLC-load-misses sleep 10
Ve son olarak hangi fonksiyonların bu cache miss’lere yol açtığını bulmak için:
sudo perf record -e LLC-load-misses -p $(pgrep myapp) sleep 10
sudo perf report
Bu üçlü kombinasyon son derece etkili: tiptop dashboard’u sürekli açık tutarak anomaliyi yakalar, perf stat ile sayısal doğrulama yaparsınız, perf report ile kaynak koda inersiniz.
Dikkat Edilmesi Gereken Noktalar
PMU sayaçları fiziksel bir kaynaktır ve sayısı sınırlıdır. Bir Intel Core işlemcide genellikle 4 programlanabilir PMU sayacı bulunur. Aynı anda birden fazla tiptop ya da perf örneği çalıştırırsanız, çekirdek sayaçları zaman paylaşımıyla (multiplexing) okur. Bu durumda değerler tahmin yoluyla hesaplanır ve hata payı artar. Konsol çıktısında * işareti görüyorsanız, o değer multiplexing ile elde edilmiştir.
Sanallaştırılmış ortamlarda PMU erişimi kısıtlı olabilir. VMware ve KVM bazı sayaçları guest’e geçirir ama tamamını değil. AWS EC2’de bare metal instance’lar PMU’ya tam erişim verir, diğer instance tiplerinde kısıtlama olabilir. Azure ve GCP’de de benzer durumlar söz konusu.
Container ortamlarında ise durum daha karmaşık. Docker container içinde çalışan bir süreci izlemek için container’ı --privileged ile başlatmanız ya da SYS_PERF_EVENT capability’sini vermeniz gerekebilir:
docker run --cap-add SYS_PERF_EVENT myimage
Kubernetes’te bu capability’yi pod spec’e eklemeniz gerekir:
securityContext:
capabilities:
add:
- SYS_PERF_EVENT
Sonuç
tiptop, sysadmin ve DevOps toolbox’ına mutlaka girmesi gereken bir araç. Özellikle “CPU yüksek ama neden?” sorusunu yanıtlamakta, ya da optimizasyon çalışmalarının gerçekten fark yaratıp yaratmadığını ölçmekte biçilmiş kaftan.
Kullanmaya başlamak için önce varsayılan ekranla oturup bir süre sadece IPC kolonunu izleyin. Uygulamalarınızın “normal” IPC değerini öğrenin. Sonra bu baseline’dan sapmaları takip edin. Bir deployment sonrası IPC %30 düştüyse, kod değişikliği memory access patternlerini bozmuş demektir; bunu hiçbir APM aracı size söylemez.
tiptop, perf, flamegraph ve vmstat birlikte kullanıldığında, neredeyse her performans probleminin kökünü bulabilirsiniz. Donanım sayaçları yalan söylemez: cycle’lar, instruction’lar ve cache miss’ler ham gerçeği gösterir. Bu gerçeği okumayı öğrenmek, performans mühendisliğinde üst lige çıkmak anlamına gelir.
