John Carmack ile ilişkilendirilen performans-öncelikli zihniyete dair pratik bir kılavuz: profil çıkarma, frame-time bütçeleri, ödünler ve karmaşık gerçek zamanlı sistemleri teslim etme.

John Carmack sık sık oyun motorlarının efsanesi olarak görülür, ama işe yarayan kısım mitoloji değil—tekrarlanabilir alışkanlıklardır. Bu, bir kişinin tarzını kopyalamak veya “dahi hamleleri” varsaymakla ilgili değil. Bu, özellikle teslim tarihleri ve karmaşıklık arttığında daha hızlı, daha akıcı yazılıma güvenilir şekilde götüren pratik ilkelerle ilgili.
Performans mühendisliği, yazılımın gerçek donanımda, gerçek koşullar altında bir hız hedefini karşılamasını sağlamak—doğruluğu bozmayarak—anlamına gelir. Bu, “her ne pahasına olursa olsun hızlı yap” demek değildir. Disiplinli bir döngüdür:
Bu zihniyet Carmack’in işlerinde tekrar tekrar görünür: veriye göre tartış, değişiklikleri açıklanabilir tut ve sürdürülebilir yaklaşımları tercih et.
Gerçek zamanlı grafikler affetmez çünkü her frame’in bir zamanı vardır. Kaçırırsanız kullanıcı bunu anında takılma, giriş gecikmesi veya düzensiz hareket olarak hisseder. Diğer yazılımlar verimsizliği kuyrukların, yükleme ekranlarının veya arka plan işlerinin arkasına saklayabilir. Bir renderer müzakere edemez: ya zamanında bitirirsiniz ya da bitiremezsiniz.
Bu yüzden dersler oyunların ötesine genellenir. Sıkı gecikme gereksinimi olan her sistem—UI, ses, AR/VR, ticaret, robotik—bütçelerle düşünmekten, darboğazları anlamaktan ve ani sıçramalardan kaçınmaktan fayda sağlar.
Kendi işinizde uygulayabileceğiniz kontrol listeleri, kestirimler ve karar kalıpları alacaksınız: frame-time (veya gecikme) bütçelerini nasıl belirleyeceğiniz, optimize etmeden önce nasıl profil çıkaracağınız, hangi “tek şeyi” seçeceğiniz ve performansın gecikmiş bir panik değil, rutin hâline gelmesini nasıl önleyeceğiniz.
Carmack tarzı performans düşüncesi basit bir anahtar değişimle başlar: birincil birim olarak “FPS” hakkında konuşmayı bırakın ve frame süresi hakkında konuşmaya başlayın.
FPS ters bir oran olduğu için (“60 FPS” iyi gelir, “55 FPS” yakın görünür), ama kullanıcı deneyimi her frame'in ne kadar sürdüğüne ve aynı zamanda bu sürelerin ne kadar tutarlı olduğuna bağlıdır. 16.6 ms'den 33.3 ms'ye atlamak, ortalama FPS hâlâ makul görünse bile anında fark edilir.
Gerçek zamanlı bir ürünün sadece “daha hızlı render et”ten fazlası olan birden çok bütçesi vardır:
Bu bütçeler etkileşir. GPU zamanını azaltmak için CPU ağırlıklı batching yapmak geri tepebilir; belleği azaltmak streaming veya decompression maliyetlerini artırabilir.
Hedefiniz 60 FPS ise toplam bütçeniz frame başına 16.6 msdir. Kabaca bir dağılım şöyle olabilir:
CPU veya GPU bütçeyi aşarsa frame kaçırırsınız. Bu yüzden ekipler “CPU-bound” veya “GPU-bound” diye konuşur—rapor için etiket değil, bir sonraki milisaniyenin nereden gerçekçi şekilde gelebileceğini seçmek için bir yol.
Mesele yüksek uç bir PC'de “en yüksek FPS” peşinde koşmak değil. Mesele, hedef kitleniz için yeterince hızlının ne olduğunu—donanım hedefleri, çözünürlük, pil, termal ve giriş tepkiselliği—tanımlamak ve sonra performansı yönetip savunabileceğiniz açık bütçeler gibi ele almaktır.
Carmack’in varsayılan hamlesi “optimize et” değil, “doğrula”dır. Gerçek zamanlı performans sorunları, GC duraklamaları, “yavaş shader’lar”, “çok fazla draw call” gibi inandırıcı hikâyelerle doludur—ve bunların çoğu sizin build’inizde, sizin donanımınızda yanlış çıkar. Profil çıkarma, sezgiyi kanıta dönüştürmenin yoludur.
Profillemeyi son dakika kurtarma aracı değil birinci sınıf bir özellik gibi ele alın. Frame sürelerini, CPU ve GPU zaman çizelgelerini ve bunları açıklayan sayımları (üçgenler, draw call'lar, durum değişiklikleri, allocation'lar, mümkünse cache miss'ler) yakalayın. Hedef bir soru sormaktır: zaman gerçekten nereye gidiyor?
Yararlı bir model: her yavaş frame’de bir şey sınırlayıcı faktördür. Belki GPU ağır bir pass'ta takılmıştır, belki CPU animasyon güncellemesinde takılmıştır ya da ana iş parçacığı senkronizasyonda bekliyordur. Önce o kısıtlamayı bulun; geri kalan her şey gürültüdür.
Disiplinli bir döngü sizi aşırı değişiklikten kurtarır:
İyileşme net değilse, yardımcı olmadığını varsayın—çünkü büyük olasılıkla bir sonraki içerik düşüşünde ayakta kalmaz.
Performans çalışması kendini kandırmaya çok açıktır:
Önce profil çıkarmak çabanızı odaklar, ödünlerinizi gerekçelendirir ve değişikliklerinizi incelemede savunulması kolay kılar.
Gerçek zamanlı performans sorunları her şey aynı anda oluyormuş gibi hissettirir: oyun mantığı, render, streaming, animasyon, UI, fizik. Carmack’in içgüdüsü gürültüyü kesip dominant sınırlandırıcıyı—şu anda frame süresini belirleyen tek şeyi—tespit etmektir.
Çoğu yavaşlama birkaç kovadan birine girer:
Ama amaç etiketlemek değil—doğru kaldıracı seçmektir.
Birkaç hızlı deney gerçekten neyin kontrol ettiği söyleyebilir:
On küçük sistemden %1 kesmek nadiren kazanım sağlar. Her frame tekrar eden en büyük maliyeti bulun ve ona saldırın. Tek bir 4 ms'lik suçluyu kaldırmak, haftalarca mikro-optimizasyondan daha etkilidir.
Büyük taşı düzelttikten sonra, bir sonraki büyük taş görünür olur. Bu normal. Performans çalışmasını bir döngü gibi görün: ölç → değiştir → yeniden ölç → yeniden önceliklendir. Amaç mükemmel bir profil değil; öngörülebilir frame süresine doğru istikrarlı ilerlemedir.
Ortalama frame süresi iyi görünse bile deneyim hâlâ kötü olabilir. Gerçek zamanlı grafikler en kötü anlarla yargılanır: büyük bir patlama sırasında düşen frame, yeni odaya girerken oluşan takılma, menü açıldığında ani donma. Bunlar tail latency—nadir ama kullanıcı tarafından hissedilen yavaş framelerdir.
Bir oyunun çoğunlukla 16.6 ms çalışıp her birkaç saniyede 60–120 ms'e sıçraması “bozuk” hissedilir, ortalama hâlâ 20 ms yazdırsa bile. İnsanlar ritme duyarlıdır. Tek bir uzun frame giriş öngörülebilirliğini, kamera hareketini ve ses/görüntü senkronunu bozar.
Spike'lar genellikle eşit dağılmamış işten gelir:
Amaç pahalı işleri öngörülebilir yapmak:
Sadece ortalama FPS çizgisi çizmeyin. Frame başına zamanlamaları kaydedin ve görselleştirin:
En kötü %1 framelerinizi açıklayamıyorsanız performansı gerçekten açıklamamışsınızdır.
Performans çalışması, her şeyi aynı anda elde edebileceğiniz yalanını bıraktığınız anda kolaylaşır. Carmack tarzı ekipleri ödünü yüksek sesle adlandırmaya iter: ne alıyoruz, ne ödüyoruz ve farkı kim hissediyor?
Çoğu karar birkaç eksen üzerine oturur:
Bir değişiklik bir ekseni iyileştirip üçünü gizlice zorlayorsa bunu belgeleyin. “Daha yumuşak gölgeler için GPU'ya 0.4 ms ve 80 MB VRAM ekliyor” kullanılabilir bir ifadedir. “Daha iyi görünüyor” değil.
Gerçek zamanlı grafikler mükemmelik değil; tutarlı bir hedefe ulaşmakla ilgilidir. Şöyle eşikler üzerinde anlaşın:
Ekip, örneğin 1080p'de referans GPU'da 16.6 ms hedefinde anlaştığında, tartışmalar somutlaşır: bu özellik bizi bütçenin altına mı sokuyor yoksa başka bir yeri düşürmeyi mi zorunlu kılıyor?
Emin olmadığınızda geri alınabilir seçenekleri seçin:
Geri alınabilirlik takvimi korur. Güvenli yolu gönderip iddialı olanı toggle arkasında tutabilirsiniz.
Görünmeyen kazanımlar için aşırı mühendislikten kaçının. Ortalama %1 iyileştirme genellikle bir ay süren kompleksiteye değmez—ta ki takılmayı ortadan kaldırmıyor, giriş gecikmesini düzeltmiyor veya kritik bir bellek çökmesini önlemiyorsa. Oyuncuların hemen fark edeceği değişiklikleri önceliklendirin, gerisi bekleyebilir.
Performans çalışması, program doğru olduğunda dramatik şekilde kolaylaşır. Birçok “optimizasyon” zamanı aslında performans gibi görünen doğruluk hatalarını kovalamaktır: tekrarlanan işten kaynaklanan istemeden O(N²) döngü, bir bayrağın sıfırlanmaması yüzünden iki kez koşan render pass, yavaşça frame süresini artıran bellek sızıntısı veya rastgele takılmalara dönüşen yarış koşulu.
Stabil, öngörülebilir bir motor ölçümleri temiz yapar. Davranış çalıştırmalar arasında değişiyorsa profillere güvenemezsiniz ve gürültüyü optimize etmeye başlarsınız.
Disiplinli mühendislik uygulamaları hızı destekler:
Birçok frame-time spike'ı “Heisenbug” gibidir: logging eklediğinizde veya debugger ile ilerlediğinizde kaybolurlar. Çözüm deterministik yeniden üretimdir.
Küçük, kontrollü bir test harness'i oluşturun:
Bir takılma ortaya çıktığında, 100 kere oynatabilen bir butonunuz olsun—“bazen 10 dakika sonra oluyor” gibi belirsiz raporlar değil.
Hız işi küçük, incelenebilir değişikliklerden fayda görür. Büyük refactorlar aynı anda birçok arıza modu yaratır: regresyonlar, yeni allocation'lar, gizli ek işler. Dar farklar hangi sorunun frame süresinde ne değiştirdiğini yanıtlamayı kolaylaştırır.
Buradaki disiplin bürokrasi değil—ölçümlerin güvenilir kalmasını sağlar, böylece optimizasyon batıl inanç yerine doğrudan sonuçlara dayanır.
Gerçek zamanlı performans sadece “daha hızlı kod” ile ilgili değildir. İşin CPU ve GPU'nun verimli yapacağı şekilde düzenlenmesiyle ilgilidir. Carmack sık sık basit bir gerçeği vurguladı: makine literal olarak hareket eder. Öngörülebilir veriyi sever ve önlenebilir overhead'den nefret eder.
Modern CPU'lar inanılmaz hızlıdır—ta ki belleğe bakmak için beklemeye başlayana kadar. Verileriniz birçok küçük obje arasında dağılmışsa CPU pointer peşinde koşmakla uğraşır; matematik yapmak yerine.
Kullanışlı bir zihin modeli: on madde için on küçük alışverişe çıkmayın. Hepsini bir arabaya koyun ve rafları bir kez dolaşın. Koddaki karşılığı, sık kullanılan değerleri birbirine yakın tutmak (genellikle diziler veya sık paketlenmiş struct'lar) böylece her cache line getirildiğinde gerçekten kullanacağınız veriyi getirmesidir.
Sık allokasyonlar gizli maliyetler yaratır: allocator overhead, bellek parçalanması ve sistemin toparlanmak zorunda kaldığı öngörülemeyen duraklamalar. Her allokasyon “küçük” olsa bile, düzenli akışı frame başına ödeyeceğiniz bir vergiye dönüşebilir.
Yaygın çözümler kasıtlı olarak sıkıcıdır: buffer'ları yeniden kullanın, obje havuzları kullanın ve sıcak yollar için uzun ömürlü tahsisleri tercih edin. Amaç zeka değil tutarlılıktır.
Frame zamanının şaşırtıcı bir kısmı bookkeeping'e gidebilir: state değişiklikleri, draw call'lar, sürücü işi, syscall'lar ve thread koordinasyonu.
Batching rendering ve simülasyonun “tek büyük araba” versiyonudur. Birçok küçük operasyon yerine benzer işleri gruplayın ki pahalı sınırları daha az kez geçin. Çoğu zaman, overhead'i azaltmak bir shader'ı veya iç döngüyü mikro-optimize etmekten daha fazla zaman kazandırır—çünkü makine çalışmaya hazırlanmak yerine gerçekten çalışmaya daha fazla zaman ayırır.
Performans işi sadece daha hızlı kod değil—aynı zamanda daha az kod sahibi olmaktır. Karmaşıklığın bir maliyeti vardır: hatalar izole etmek daha uzun sürer, düzeltmeler daha dikkatli test gerektirir, iterasyon yavaşlar çünkü her değişiklik daha fazla parçaya dokunur ve regresyonlar nadiren kullanılan yollardan sızar.
“Clever” bir sistem şık görünebilir ta ki son teslim tarihine yaklaşana kadar ve bir frame spike sadece bir harita, bir GPU veya bir ayar kombinasyonunda ortaya çıkana kadar. Her ekstra feature flag, fallback yolu ve özel durum anlamanız ve ölçmeniz gereken davranış sayısını çarpıyor. Bu karmaşıklık sadece geliştirici zamanını boşa harcamaz; genellikle çalışma zamanında da ekstra branch'lar, allocation'lar, cache miss'ler ve senkronizasyon gibi görülmesi zor maliyetler ekler.
İyi bir kural: performans modelini birkaç cümlede bir takıma açıklayamıyorsanız, muhtemelen onu güvenilir şekilde optimize edemezsiniz.
Basit çözümler iki avantaja sahiptir:
Bazen en hızlı yol bir özelliği kaldırmaktır, bir seçeneği kesmektir veya birden çok varyantı tek bir şeye daraltmaktır. Daha az özellik, daha az kod yolu, daha az durum kombinasyonu ve performansın gizlice bozulacağı daha az yer demektir.
Kod silmek aynı zamanda bir kalite hamlesidir: ortadan kaldırdığınız modülün oluşturabileceği en iyi hata, onu silmektir.
Patch (cerrahi düzeltme) uygundur:
Refactor uygundur:
Basitlik “daha az iddialı” demek değildir. Performansın en çok önemi olduğu zamanda anlaşılır kalacak tasarımlar seçmektir.
Performans çalışması yerleşik kalırsa işe yarar. İşte performans regresyon testi: yeni bir değişikliğin ürünü daha yavaş, daha az akıcı veya bellekte daha ağır yapıp yapmadığını saptamanın tekrarlanabilir yolu.
Fonksiyonel testlerin aksine ("çalışıyor mu?" sorusunu cevaplar), regresyon testleri "aynı hızda hissetmeye devam ediyor mu?" sorusunu yanıtlar. Bir build %100 doğru olabilir ama eğer frame süresine 4 ms ekliyor veya yüklemeyi iki katına çıkarıyorsa kötü bir sürüm olabilir.
Laboratuvara ihtiyacınız yok—sadece tutarlılık.
Küçük bir set baseline sahne seçin: bir GPU-ağır görünüm, bir CPU-ağır görünüm ve bir “en kötü durum” stres sahnesi. Bunları sabit ve scriptlenmiş tutun ki kamera yolu ve input her runda aynı olsun.
Sabit donanım üzerinde çalıştırın (bilinen bir PC/console/devkit). Sürücü, OS veya saat ayarlarını değiştirirseniz bunu kaydedin. Donanım/yazılım kombinasyonunu test düzeneğinin bir parçası gibi ele alın.
Sonuçları versiyonlanmış bir geçmişe kaydedin: commit hash, build konfigürasyonu, makine kimliği ve ölçülen metrikler. Amaç mükemmel sayı değil—güvenilir bir trend çizgisidir.
Tartışılmaz metrikleri tercih edin:
Basit eşikler tanımlayın (ör. p95 frame süresi %5'ten fazla gerilememeli).
Regresyonları bir sahip ve teslim tarihi olan bug gibi ele alın.
Önce bisect ile hangi değişikliğin getirdiğini bulun. Eğer regresyon sürümü bloke ediyorsa, hemen geri alın ve düzeltmeyle birlikte tekrar gönderin.
Düzelttiğinizde koruyucular ekleyin: testi saklayın, koda not ekleyin ve beklenen bütçeyi belgeleyin. Alışkanlık kazanımı zaferdir—performans sürdürülmesi gereken bir şey olur, "sonra yapılacak" değil.
“Göndermek” takvimsel bir olay değildir—mühendislik gereksinimidir. Sadece laboratuvarda iyi çalışan veya bir hafta manuel ince ayar gerektiren bir sistem tamamlanmış sayılmaz. Carmack zihniyeti gerçek dünya kısıtlarını (donanım çeşitliliği, dağınık içerik, öngörülemez oyuncu davranışı) baştan beri şartnameye dahil eder.
Sürüme yaklaşırken mükemmellik öngörülebilirlikten daha değerli değildir. Pazarlık götürmez nelerin doğru olması gerektiğini sade ifadelerle tanımlayın: hedef FPS, en kötü frame süresi spike'ları, bellek limitleri ve yükleme süreleri. Bunları ihlal eden her şey bir bug olarak ele alın. Bu, performans çalışmasını isteğe bağlı optimizasyondan güvenilirlik işine çevirir.
Tüm yavaşlamalar eşit derecede önemli değildir. Önce kullanıcı tarafından görüleni düzeltin:
Profil disiplini burada karşılığını verir: hangi sorunun “büyük” olduğunu tahmin etmiyorsunuz, ölçülmüş etkiye göre seçiyorsunuz.
Geç döngüde performans çalışması risklidir çünkü “düzeltmeler” yeni maliyetler getirebilir. Aşamalı dağıtım kullanın: önce enstrümantasyonu ekleyin, sonra değişikliği toggle arkasında gönderin, sonra kapsama genişletin. Özellikle otomatik algılama için performans-güvenli varsayılanları tercih edin—görünüşü biraz daha az süslü yapmak, kararsız görünmekten iyidir.
Eğer birden fazla platform veya seviye gönderiyorsanız, varsayılanları bir ürün kararı olarak ele alın: kararsız hissetmektense biraz daha az gösterişli görünmek daha iyidir.
Ödünleri sonuçlara çevirin: “Bu efekt orta seviye GPU'larda her frame 2 ms maliyet getiriyor, bu da çatışma anında 60 FPS altına düşmemize neden olabilir.” Seçenekler sunun, ders vermeyin: çözünürlüğü düşür, shader'ı sadeleştir, spawn oranını sınırlayın veya daha düşük hedefi kabul et. Kısıtlamalar somut tercihler ve kullanıcı etkisiyle çerçevelendiğinde daha kolay kabul edilir.
Yeni bir motor veya yeniden yazım gerekmez. Carmack tarzı performans düşüncesini benimsemek için tekrarlanabilir bir döngüye ihtiyacınız var: performansı görünür, test edilebilir ve kazara bozulması zor hale getirin.
Ölç: frame süresi ve ana alt sistemler için bir temel yakalayın (ortalama, p95, en kötü spike).
Bütçe: CPU ve GPU için frame başına bir bütçe belirleyin (bellek sıkışıktaysa bellek de). Bütçeyi özellik hedefinin yanına yazın.
İzole et: maliyeti minimal bir sahnede veya testte yeniden üretin. Üretemezseniz güvenilir şekilde düzeltemezsiniz.
Optimize et: aynı anda bir şeyi değiştirin. İş azaltan değişiklikleri tercih edin, sadece “daha hızlı yapan” değil.
Doğrula: yeniden profil çıkarın, deltoları karşılaştırın ve kalite/regresyonları kontrol edin.
Belgeleyin: ne değişti, neden yardımcı oldu ve gelecekte neye dikkat edileceğini kaydedin.
Bu alışkanlıkları ekip çapında operasyonelleştirmek istiyorsanız, kilit unsur pürüzleri azaltmaktır: hızlı deneyler, tekrarlanabilir harness'lar ve kolay geri alma. Koder.ai burada motoru değil çevreleyici araçları inşa ederken yardımcı olabilir. Vibe-coding platformu olarak gerçek, dışa aktarılabilir kaynak kodu (web uygulamaları React'te; backend Go + PostgreSQL; mobil Flutter) üretebildiği için iç panolar, frame-time percentil geçmişi ve “performans inceleme” formları gibi dahili araçları hızla açabilirsiniz. Anlık görüntüler ve geri alma, “tek bir şeyi değiştir, yeniden ölç” döngüsüyle pratikte iyi eşleşir.
Eğer daha fazla pratik rehber isterseniz, /blog bölümünü inceleyin veya ekiplerin bunu /pricing üzerinde nasıl operasyonelleştirdiğine bakın.
Frame süresi, her bir frame'in milisaniye (ms) cinsinden zamanıdır ve CPU/GPU'nun ne kadar iş yaptığıyla doğrudan eşleşir.
Bir hedef seçin (ör. 60 FPS) ve bunu sert bir zamana (16.6 ms) çevirin. Sonra bu süreyi açık bütçelere bölün.
Örnek başlangıç noktası:
Bunları ürün gereksinimi olarak görün ve platform, çözünürlük, termal ve giriş gecikmesi hedeflerine göre ayarlayın.
Testlerinizi tekrarlanabilir hale getirin, sonra hiçbir şeyi değiştirmeden önce ölçün.
Zamanın gerçekte nereye gittiğini bilmeden neyi optimize edeceğinize karar vermeyin.
Hızlı, hedefe yönelik deneyler çalıştırın:
Sistemi yeniden yazmadan önce dominant maliyeti milisaniye cinsinden adlandırabildiğinizden emin olun.
Çünkü kullanıcılar ortalamayı değil en kötü frameleri hisseder.
Takip edin:
Ortalama 16.6 ms ama her birkaç saniyede 80 ms'e fırlayan bir yapı hâlâ bozuk hissedilir.
Pahalı işleri öngörülebilir ve planlı hale getirin:
Ayrıca spike'ları loglayın ki yeniden üretebilesiniz ve sadece “umarım kaybolur” demeyin.
Ödünleri sayılara ve kullanıcı etkisine dönüştürün.
Şöyle ifadeler kullanın:
Sonra kararı şu eşiklere göre verin:
Çünkü kararsız doğruluk performans verisini güvenilmez kılar.
Pratik adımlar:
Davranış her çalıştırmada değişiyorsa, gürültüyü optimize etmiş olursunuz, darboğazı değil.
Çoğu “hızlı kod” işi aslında “bellek ve yük” işidir.
Odaklanın:
Çoğu zaman, overhead'i kesmek inner loop'ı optimize etmekten daha büyük kazanım getirir.
Performansı ölçülebilir, tekrarlanabilir ve istemeden bozulması zor hale getirin.
Emin değilseniz geri alınabilir kararları (feature flag, kalite kademeleri) tercih edin.
Regresyon yakalandığında: bisect yapın, bir sahibi atayın ve eğer sürümü engelliyorsa hemen geri alın.