Bir GPU node’u, bir raf dolusu CPU makinesinden saatte daha fazlaya mal olur ve finansın onun hakkında sorduğu soru, her şey hakkında sorduğu soruyla aynıdır: bunu kim kullandı ve ne kadar? CPU, bellek ve disk için bunu cevaplayabilirsiniz — cgroup’lar bunu process başına hesaplar, cAdvisor pod başına raporlar, Prometheus ekip başına toplar. GPU içinse çoğu kümede dürüst cevap, kimsenin bilmediğidir. Filodaki en pahalı kaynağın parasını ödüyorsunuz ve onun tek bir kuruşunu bile atfedemiyorsunuz.

Bu, doldurmayı unuttuğunuz bir araç boşluğu değil. Yapısaldır: GPU, yığınınızın geri kalanının dayandığı muhasebe düzleminin dışındadır. Bu yazı nedeniyle ve atfetmeyi geri kazanmak için eBPF kullanmakla ilgili — ve eBPF’in ne görebildiği ve ne göremediğine dair sert bir çizgiyle birlikte, çünkü buradaki en pahalı hata, bir aracın fiziksel olarak cevaplayamadığı bir soruyu cevapladığına inanmaktır.

GPU mevcut metriklerinize neden görünmez

Üç ayrı körlük üst üste yığılır.

cgroup’lar GPU’yu hesaplamaz. Bir cgroup, CPU, bellek, block I/O ve PID’leri hesaplayan ve sınırlayan bir kernel yapısıdır. GPU bunların hiçbiri değil. Compute ve framebuffer (VRAM), NVIDIA kernel driver’ı ve userspace CUDA runtime’ı tarafından yönetilir ve cgroup hesaplamasına opaktır. Bir device cgroup controller’ı var, ama o yalnızca device node’larına (/dev/nvidia0 ve dostları) erişimi geçitler — izin ver ya da reddet. Tek bir saniye GPU zamanını ya da bir megabayt VRAM’i hesaplamaz. Yani size pod başına CPU ve bellek veren tüm cAdvisor → Prometheus boru hattının, kuruluş gereği, GPU hakkında söyleyecek hiçbir şeyi yoktur.

nvidia.com/gpu bir tahsis sayısıdır, bir kullanım sinyali değil. Kubernetes GPU’ları, onları kubelet’e extended resource nvidia.com/gpu olarak kaydeden NVIDIA device plugin’i üzerinden öğrenir. Pod’lar bunu bir integer olarak ister — bütün GPU’lar. Scheduler istenen sayıyı mevcut sayıyla eşler. Tahsis katmanının bildiği tek şey budur. Bir GPU istemek, bir GPU kullanmak değildir. Bir pod bütün bir cihazı tutabilir — ve bütün cihazın faturasını ödeyebilir — onu %3’te sürerken. Karşı chargeback yapabileceğiniz tahsis sayısı, tam da tüketim hakkında size hiçbir şey söylemeyen sayıdır.

nvidia-smi’nin kullanım sayısı bile size yalan söyler. nvidia-smi’ye uzanırsınız ve utilization.gpu alanı kurtuluş gibi görünür. Sandığınız şey değil. NVML onu şöyle tanımlar: örnekleme periyodu boyunca bir ya da daha fazla kernel’in çalıştığı zamanın yüzdesi. Zamansal varlığı — GPU hiç meşgul muydu — ölçer, ne kadarının meşgul olduğunu değil. Onlarca SM’den birini işgal eden tek thread’lik bir kernel %100’e yakın raporlayabilir. Microsoft, A100’ler üzerinde 8B parametreli bir modeli servis ederken bellek-bağımlı decode fazında %10’un altında compute kullanımı raporlamıştır — naif bir “kullanım” okuması o GPU’ları dolu sayacakken. utilization.gpu üzerinden chargeback yaparsanız, silikon neredeyse boştayken “meşgul” diyen bir sayı üzerinden faturalandırıyorsunuzdur.

Yani: tahsis katmanı sayıyı-değil-kullanımı bilir, cgroup’lar hiçbir şey bilmez ve tek kolay yüzde yanlış şeyi ölçer. Boşluk budur.

İki soru ve neden farklı araçlar gerektirdikleri

Herhangi bir araçtan önce iki soruyu ayırın, çünkü onları karıştırmak temel hatadır — bir aracın çözdüğü problemi eldeki problemle karıştırmakla aynı şekil.

  • Atfetme — GPU işini kim yaptı ve ne kadar? Bu FinOps sorusudur. Pod başına, ekip başına GPU aktivitesi hesabı gerektirir: hangi workload kernel başlattı, VRAM tahsis etti, veri taşıdı ve ne kadar süreyle. Chargeback bunun üzerinden koşar.
  • Verimlilik — silikon ne kadar iyi kullanıldı? SM’ler gerçekten doluydu mu, tensor core’lar aktif miydi, darboğaz bellek bant genişliği miydi? Bu performans sorusudur. Bir ekibin harcamasının haklı olup olmadığını söyler, ama kimin harcaması olduğunu söyleyemez.

Bunlar iki farklı ölçüm düzlemine eşlenir ve aşağıdaki her şeyi örgütleyen kural şu: eBPF atfetmeyi cevaplar; GPU’nun kendi sayaçları verimliliği cevaplar. Hiçbiri diğerinin yerine geçmez.

eBPF’in görebildiği: kontrol düzlemi

eBPF kernel’de çalışır ve kprobe’lara, uprobe’lara, tracepoint’lere ve syscall’lara takılır. Okunacak bir GPU-kullanımı tracepoint’i yok — ama GPU işinin talep edildiği iki yüzey var ve ikisi de kernel’den görünür:

  • Driver ioctl sınırı. Her parça GPU işi — kernel gönderimi, bellek tahsisi, senkronizasyon — sonunda /dev/nvidiactl’a ve /dev/nvidia0…N’e bir ioctl() olur. Driver’ın giriş noktalarındaki (nvidia_unlocked_ioctl, nvidia_open) bir kprobe o trafiği görür. (Kapalı driver tarihsel olarak yalnızca tek bir tracepoint, donanım hata olayları için nvidia:nvidia_dev_xid, sunar; geri kalan her şey kprobe’lanır.)
  • CUDA kütüphane sınırı. libcuda.so / libcudart.so üzerindeki bir uprobe API’nin kendisini izler: cuLaunchKernel, cuMemAlloc, cuMemcpyHtoD, cuStreamSynchronize ve dostları. Bir giriş uprobe’unu bir dönüş uretprobe’uyla eşlemek her çağrının süresini ölçer.

Bunun atfetme olmasının nedeni, eBPF’in her hook noktasında çağıran PID/TGID’yi ve cgroup’u native olarak okumasıdır — bpf_get_current_pid_tgid ve cgroup id tam orada. Bu size PID → cgroup → pod → namespace → ekip zincirini verir, uygulama değişikliği olmadan ve NVIDIA’nın işbirliği olmadan. Pod başına şunları alırsınız: kernel-başlatma sayıları, başlatma boyutları, VRAM tahsis boyutları, memcpy hacmi ve yönü, ve çağrı zamanlaması. Bu, tamamen sınırın kernel tarafından türetilen, gerçek ve savunulabilir bir chargeback sinyalidir.

Buradaki ekosistem genç ama gerçek. Primitifler bugün işliyor — CUDA kütüphanelerini uprobe’layan ve nvidia ioctl yolunu kprobe’layan çalışan yazılar ve eğitimler var, ve bpftime eBPF mantığını GPU olaylarına bağlamayı keşfediyor. Tetragon (Cilium), Kubernetes pod kimliğiyle jenerik process_uprobe, process_kprobe ve ioctl izleme sevk eder, yani CUDA sembollerine ya da ioctl yoluna yöneltilebilir — ama bunun sevk edilen bir “GPU FinOps” özelliği değil, yazdığınız bir TracingPolicy olduğunu anlayın. Henüz baskın, anahtar-teslim bir eBPF chargeback ürünü yok. Size “tak-çalıştır eBPF GPU FinOps” satan biri, ekosistemin şu an ulaştığından öteye satıyordur.

eBPF’in göremediği: silikon

Dürüst limit bu ve bir sürümde düzeltilecek bir olgunluk problemi değil — verinin nerede yaşadığının fiziği.

eBPF kontrol düzlemini görür: API çağrıları, ioctl’lar, tahsis boyutları, başlatma sayıları ve izleyebildiğiniz yerde gönderim-tamamlanma zamanlaması. GPU’nun içini görmez. SM occupancy’sini, tensor-core kullanımını ya da erişilen bellek bant genişliğini okuyamaz, çünkü bunlar cihazda yaşayan ve yalnızca NVML / DCGM / CUPTI üzerinden açığa çıkan donanım performans sayaçlarıdır. eBPF’in onlara giden bir yolu yoktur. Bir pod’un on bin kernel başlattığını ve 40 GB VRAM tahsis ettiğini söyleyebilir; o kernel’lerin SM’leri doyurup doyurmadığını ya da onları %90 boş bırakıp bırakmadığını söyleyemez.

İkinci, daha incelikli bir limit var. eBPF’in takılabildiği ioctl sınırında bile, payload’lar büyük ölçüde opaktır. Driver’ın komut yapıları (NV_ESC_* Resource Manager API’si) karmaşık ve fiilen proprietary. Bir ioctl’ın olduğunu görebilirsiniz — komut numarasını, çağıran PID’yi, zamanlamayı — ama keyfi bir RM payload’unun semantik içeriğini decode etmek pratik dışı ve kırılgandır. İşin gerçeğini ve atfetmesini alırsınız, anlamının bedava bir okumasını değil.

Cazip bir kapıyı kapatan bir not: NVIDIA’nın açık kernel modülleri (open-gpu-kernel-modules, Turing ve sonrası) kernel arayüz katmanını açar — modül init’ini, ioctl giriş noktalarını, NV_ESC_* komut yüzeyini. Bu, neyi hook’layacağınızı anlamanıza gerçekten yardımcı olur. Ama GPU’nun beyni kapalı kalır: OS-agnostik Resource Manager core’u önceden derlenmiş bir binary blob olarak gelir ve Turing+’ta yönetimin çoğu GPU üzerindeki GSP firmware’inde koşar. Kernel modüllerini açmak, eBPF’e donanım performans sayaçlarını açmaz. Cihaz-içi limit değişmemiştir. Açık modüllerin eBPF’e SM occupancy okuttuğunu iddia eden biri, mevcut kanıtlara göre yanılıyordur.

Hâlâ ihtiyaç duyduğunuz userspace yolu: DCGM

eBPF silikonu göremediği için, cevabın verimlilik yarısı userspace’ten gelir ve standart araç, Prometheus için dcgm-exporter ile NVIDIA DCGM (Data Center GPU Manager)’dır. DCGM, GPU’nun donanım sayaçlarını driver üzerinden okur ve eBPF’in erişemediği alanları açığa çıkarır:

  • DCGM_FI_PROF_SM_ACTIVE — bir multiprocessor’da en az bir warp’ın aktif olduğu zamanın oranı, hepsinin ortalaması.
  • DCGM_FI_PROF_SM_OCCUPANCY — resident warp’ların desteklenen maksimuma oranı: gerçek occupancy.
  • DCGM_FI_PROF_PIPE_TENSOR_ACTIVE — tensor pipe’ın aktif olduğu döngülerin oranı.
  • DCGM_FI_PROF_DRAM_ACTIVE — bir bellek-bant-genişliği vekili.
  • DCGM_FI_DEV_FB_USED — gerçekten kullanımda olan framebuffer (VRAM).

Bunlar size bir ekibin pahalı tahsisinin ekmeğini kazanıp kazanmadığını söyleyen sayılardır. DCGM onları pod’lara, her GPU UUID’yi onu tutan pod’a eşleyen kubelet Pod Resources API’si (/var/lib/kubelet/pod-resources adresindeki bir gRPC servisi) üzerinden atfeder.

Ama DCGM’in atfetmesinin, tam da eBPF’in yerini hak ettiği yerde sert bir kenarı var: DCGM cihaz-seviyesi metrikler üretir, bu yüzden tek bir fiziksel GPU’yu paylaşan tüketicileri ayırt edemez. Time-slicing ya da MPS altında, bir GPU’yu paylaşan tüm pod’lar aynı, kopyalanmış cihaz-seviyesi değerleri alır — DCGM_FI_DEV_FB_USED dahil. NVIDIA’nın kendi exporter’ı, time-slicing etkinken metrikleri container’larla ilişkilendirmediğini belgeler; --kubernetes-virtual-gpus=true ile her paylaşan pod tüm fiziksel GPU’nun durumunu aynalar. MIG altında atfetme, keyfi pod’lara değil GPU-instance seviyesine kayar. Yani tam da paylaşılan-GPU durumunda — ki bu durum, bütün-GPU tahsisi para israf ettiği için var olur — DCGM size kimin ne tükettiğini söyleyemez. eBPF’in PID-seviyesi izlemesi söyleyebilir. İki araç, her birinin en zayıf olduğu dikişte birbirini tamamlar.

(En derin verimlilik profilleme için CUPTI, CUDA Profiling Tools Interface var; DCGM’in açığa çıkarmadığı sayaçları okuyabilir — ama Nsight Compute gibi metrik-replay profilleme kernel’leri birden çok kez yeniden çalıştırır ve ağır overhead taşır. Bu bir profilleme-oturumu aracıdır, her zaman açık tenant başına telemetri değil. DCGM düşük-overhead’li, örnekleme-bazlı sürekli yoldur; CUPTI ağır, derin olandır.)

Kernel-vs-userspace takası, açıkça

DüzlemAraçGörürGöremez
Kernel (kontrol)eBPFPID→pod atfetme, başlatma sayıları, tahsis boyutları, memcpy hacmi, çağrı zamanlaması — time-slicing altında pod başına dahilcihaz-içi SM/tensor occupancy, bellek bant genişliği, ioctl payload içleri
Userspace (cihaz)DCGMgerçek SM occupancy, tensor aktivitesi, DRAM aktivitesi, kullanılan VRAM — donanım sayaçlarındanpaylaşılan GPU altında (time-slicing/MPS) pod başına atfetme: tüm paylaşanlar aynı değerleri alır

eBPF düşük-overhead’lidir, uygulama değişikliği gerektirmez, vendor işbirliği gerektirmez ve PID/cgroup üzerinden native atfeder — kim ve ne kadar için doğru araç odur. DCGM silikonu okur — ne kadar iyi için doğru araç odur. Maliyetler de dürüst: uprobe’lar gerçek overhead taşır ve CUDA sembolleri versiyonludur (cuMemAlloc@CUDA_11.0 vs @CUDA_12.0), yani probe’lar dinamik sembol çözümü gerektirir ve driver yükseltmeleri boyunca kırılır; CUDA API çağrıları saniyede on-binden fazla atebilir, yani handler’lar ucuz kalmalı yoksa ölçtükleri workload’u yavaşlatırlar. DCGM kendi örnekleme overhead’i olan userspace polling’dir ve yalnızca belirli sayaç gruplarının birlikte okunabildiği bir donanım kısıtı taşır.

İkisine de neden, hangi sırayla ihtiyacınız var

Yanlış dönüş, bir aracı seçip ona diğer aracın sorusunu sormaktır — ekipleri DCGM’in cihaz-seviyesi sayıları üzerinden faturalandırıp bir GPU’yu paylaşan herkesi sessizce fazla yüklemek, ya da eBPF’in başlatma sayılarına verimlilik vekili olarak güvenip meşgul görünen bir workload’un iyi kullanıldığı sonucuna varmak. Gerçekten işleyen sıra:

1. eBPF: GPU işini pod/ekibe atfet           (kim, ne kadar — fatura)
2. DCGM: cihaz-içi verimliliği ölç           (ne kadar iyi — haklı mıydı)
3. Onları pod kimliğinde birleştir            (ekibin harcaması VE verimliliği)

Atfetme önce, çünkü finansın gerçekten sorduğu soru o ve mevcut yığınınızın hiç cevaplayamadığı o. Verimlilik sonra, çünkü faturayı bir karara dönüştürür — pahalı bir tahsisi %4 occupancy’de tutan bir ekip, artık görebileceğiniz bir ileride-lazım-olur kapasite vergisi ödüyordur; oysa önceden GPU, kimsenin açamadığı düz bir kalemdi. Pod kimliğinde birleşince, nihayet her diğer kaynak için sahip olduğunuz şeye sahip olursunuz: atfedilmiş harcama, üzerinde harekete geçecek verimlilik bağlamıyla. İki düzlem gerektirmesinin nedeni, görünmez olmasının nedeniyle aynıdır — silikon muhasebe düzleminde hiç yaşamadı ve hiçbir tek probe sınırı kat etmiyor.


İlgili: DCGM exporter belgeleri profilleme alanlarını ve pod-atfetme yolunu tanımlar; bunun yaslandığı eBPF primitifleri ebpf.io ve Tetragon’da belgelenmiştir.