ONNX Runtime 1.17 CUDA Provider VRAM Parçalanması ve BFC Arena Optimizasyonu
Blog'a Dön

ONNX Runtime 1.17 CUDA Provider VRAM Parçalanması ve BFC Arena Optimizasyonu

Buğra Şıkel

ONNX Runtime 1.17 CUDA Provider VRAM Parçalanması ve BFC Arena Optimizasyonu

Giriş

NVIDIA A10G veya T4 GPU’lar üzerinde yüksek hacimli batch inference işlemleri yürütürken karşılaşılan en kritik problemlerden biri donanım limitleri değil, bellek yönetimindeki determinizm eksikliğidir. nvidia-smi çıktısında 8 GB boş VRAM görünmesine rağmen, 600 MB’lık yeni bir tensor tahsisi sırasında alınan CUDA out of memory (OOM) hatası, doğrudan bellek parçalanmasının (memory fragmentation) bir sonucudur. Dinamik boyutlu tensorlerin saniyede binlerce kez yaratılıp yok edilmesi, GPU belleğinde küçük ve kullanılamaz boşluklar bırakır. Toplam boş alan yeterli olsa da, kesintisiz (contiguous) bir bellek bloğu bulunamadığı için süreç çöker.

ONNX Runtime (ORT) 1.17 sürümüyle birlikte CUDA Execution Provider içindeki bellek tahsis stratejileri daha da rafine edildi. BFC (Best-Fit with Coalescing) Arena allocator algoritması, bu parçalanmayı önlemek için varsayılan olarak devreye giriyor. Ancak üretim ortamında (production) varsayılan ayarları kullanmak, özellikle çoklu model barındıran sunucularda beklenmedik darboğazlar yaratır. 2023’ün son çeyreğinde yönettiğim, saniyede ortalama 450 ses dosyası işleyen Whisper-large-v3 cluster’ında, 12 saatlik kesintisiz çalışma sonrası API hata oranlarının %0.01’den %4.2’ye çıkması, doğrudan standart BFC parametrelerinin 24GB VRAM sınırlarına dayanmasından kaynaklanıyordu.

ONNX Runtime 1.17’nin sunduğu bellek havuzu yapılandırmalarını, BFC algoritmasının iç mekanizmalarını ve production ortamında uygulanması gereken kesin konfigürasyonları inceleyeceğiz. Optimizasyonların ölçülebilir etkileri üzerinden doğrudan kod düzeyinde müdahalelere odaklanacağız.

İçindekiler

  • GPU Bellek Parçalanmasının Anatomisi ve BFC Arena Mekanizması
  • ORT 1.17 CUDA Provider’da Arena Konfigürasyonu
  • Performans ve Trade-off Analizi
  • Production Önerileri
  • Sık Sorulan Sorular
  • Sonuç

GPU Bellek Parçalanmasının Anatomisi ve BFC Arena Mekanizması

Nvidia VRAM Yönetiminde OOM Paradoksu

Büyük Dil Modelleri (LLM) veya Otomatik Konuşma Tanıma (ASR) sistemlerinde dizi uzunlukları (sequence lengths) sürekli değişir. Inference sunucusuna gelen bir istek 128 token için 512 MB bellek tahsisi gerektirirken, bir sonraki istek 2048 token için 2.4 GB talep edebilir. Standart C++ runtime, bu süreçte her tensor için doğrudan cudaMalloc ve cudaFree API’lerini çağırır. Bu durum zamanla VRAM üzerinde “external fragmentation” (dış parçalanma) oluşturur.

Dış parçalanma, bellekteki boş alanların toplamı istenen tahsis boyutundan büyük olduğu halde, bu alanların bitişik (contiguous) olmaması nedeniyle bellek tahsisinin başarısız olması durumudur.

İşletim sistemi seviyesindeki CUDA sürücüsü, 2.4 GB kesintisiz bir fiziksel bellek bloğu aradığında, rastgele dağılmış 100 MB’lık aktif tensorler yüzünden bu bloğu bulamaz ve sistemde 12 GB boş alan olmasına rağmen cudaErrorMemoryAllocation fırlatır.

BFC (Best-Fit with Coalescing) Algoritmasının ORT 1.17’deki Davranışı

Doug Lea’nın geleneksel malloc implementasyonundan ilham alan BFC, her seferinde sürücü seviyesinde tahsis yapmak yerine belleği tek bir devasa yığın (chunk) olarak rezerve eder. ORT 1.17, model yüklendiğinde ve CUDA Provider başlatıldığında bu rezerve işlemiyle bir Arena (bellek havuzu) oluşturur.

Yeni bir işlem için tensor gerektiğinde, BFC ağacı (binning structure) taranır. İstenen boyutu karşılayabilecek en küçük boş blok (Best-Fit) seçilir. Model inference adımı tamamlanıp tensor serbest bırakıldığında ise, serbest bırakılan blok etrafındaki boş bloklarla anında birleştirilir (Coalescing). Bu birleştirme adımı, küçük boşlukların zamanla devasa contiguous bloklara dönüşmesini garanti altına alır. ORT 1.17’de bu işlem O(1) zaman karmaşıklığında çalışacak şekilde optimize edilmiştir, böylece allocation overhead’i 140ms seviyelerinden 0.02ms seviyelerine çekilir.

ORT 1.17 CUDA Provider’da Arena Konfigürasyonu

Device Memory Pattern ve Arena Ayarlarının Kesişimi

BFC Arena’nın dezavantajı, başlangıçta ve büyüme (extend) anlarında bellek kapasitesini agresif kullanmasıdır. Varsayılan olarak arena_extend_strategy parametresi kNextPowerOfTwo (0) değerine ayarlanmıştır. Bu strateji, bellek havuzu dolduğunda, havuzun mevcut boyutunu 2’nin kuvvetleri şeklinde artırır. 24 GB VRAM kapasiteli bir NVIDIA A10G üzerinde çalışırken, arena boyutunuz 16 GB’a ulaştığında ve 500 MB ekstra belleğe ihtiyaç duyduğunuzda, algoritma havuzu 32 GB’a genişletmeye çalışır. Bu durum, donanım limitlerini aştığı için anında OOM hatasına neden olur.

Bu spesifik senaryoda arena_extend_strategy değerini kSameAsRequested (1) olarak yapılandırmak hayati önem taşır. Bu sayede bellek havuzu yalnızca tam olarak ihtiyaç duyulan byte miktarı kadar genişletilir. Ayrıca gpu_mem_limit parametresi ile Arena’nın GPU üzerinde işgal edebileceği maksimum limit hard-coded olarak sınırlandırılmalıdır.

Python ve C++ Binding’lerinde Parametre Enjeksiyonu

Aşağıdaki Python kodu, Triton Inference Server veya FastAPI arkasında çalışan bir ORT session’ı başlatırken bellek havuzu parametrelerinin nasıl enjekte edileceğini gösterir.


import onnxruntime as ort
import multiprocessing

# GPU VRAM sınırını bayt cinsinden belirleme (Örn: 24GB VRAM için 20GB limit - ~83%)
GPU_MEM_LIMIT = 20 * 1024 * 1024 * 1024

providers = [
    (
        "CUDAExecutionProvider",
        {
            "device_id": 0,
            "arena_extend_strategy": "kSameAsRequested",  # kNextPowerOfTwo yerine kullan
            "gpu_mem_limit": GPU_MEM_LIMIT,
            "cudnn_conv_algo_search": "EXHAUSTIVE",
            "do_copy_in_default_stream": True,
            "enable_cuda_graph": False # Değişken input size varsa false kalmalı
        },
    ),
    "CPUExecutionProvider",
]

sess_options = ort.SessionOptions()
# Thread optimizasyonları
sess_options.intra_op_num_threads = multiprocessing.cpu_count()
sess_options.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL

# Modelin yüklenmesi
session = ort.InferenceSession(
    "model_quantized_int8.onnx",
    sess_options=sess_options,
    providers=providers
)

Yukarıdaki konfigürasyonda enable_cuda_graph değerinin False bırakılması kritiktir. CUDA Graphs, statik tensor boyutları için performansı %15 artırabilir ancak dinamik boyutlar (dynamic axes) kullanıldığında, her farklı batch boyutu için yeni bir graf tahsis edeceği için bellek tüketimini katlayarak Arena’nın limitlerini çok hızlı tüketir.

Performans ve Trade-off Analizi

BFC Arena’nın kullanılmasının veya sistem seviyesi (System Allocator) tahsisatçının tercih edilmesinin farklı sistem mimarilerinde doğrudan etkileri vardır. Aynı 24 GB VRAM donanımında, ResNet-50 tabanlı bir pipeline ile gerçekleştirilen benchmark sonuçları aşağıdaki tabloda özetlenmiştir.

Metrik BFC Arena (kNextPowerOfTwo) BFC Arena (kSameAsRequested) Arena Kapalı (System Allocator)
P99 Inference Latency 12.4 ms 12.8 ms 18.7 ms
Maximum VRAM İşgali 23.8 GB (OOM Riski) 14.2 GB 8.9 GB (Başlangıç) -> 24GB (Zamanla)
Allocation Overhead / Tensor 0.01 ms 0.03 ms 0.45 ms (Zamanla artar)
Çoklu Model Desteği (Multi-tenancy) Zayıf (Tüm VRAM’i bloke eder) Orta (Kontrollü büyüme) İyi (Sadece gerektiğinde tahsis)

Trade-off Analizi: Hangi Senaryoda Hangisi Tercih Edilmeli?

  • Dedike Yüksek Hacimli Inference (High-Throughput): Sunucu tek bir modeli (örneğin Llama-3-8B) serve ediyorsa ve RPS (Request Per Second) çok yüksekse, BFC Arena kesinlikle açık olmalıdır. Sistem tahsisatçısının (system allocator) getireceği kernel içi bekleme süreleri, saniyede binlerce isteğin olduğu durumda darboğaz oluşturur.
  • Çoklu Model Paylaşımı (Multi-tenancy): Aynı GPU üzerinde hem bir embedding modeli, hem de bir LLM modeli farklı process’ler üzerinden koşturuluyorsa, Arena’nın kapalı tutulması veya her iki process için gpu_mem_limit parametresinin 10 GB gibi kesin ve aşılmaz değerlere set edilmesi şarttır. Aksi takdirde process’lerden biri VRAM’in %90’ını kendi Arena’sı için rezerve eder, diğer process başlatılamaz.
  • Kenar Bilişim (Edge Devices): Jetson Orin Nano gibi 8 GB paylaşımlı belleğe sahip sistemlerde, BFC Arena’nın açık olması işletim sisteminin bellek yönetimini (OOM Killer) tetikleyebilir. Bu cihazlarda Arena kapatılarak, işletim sisteminin swap ve page management mekanizmalarına güvenmek P99 gecikmesini 4-5 ms artırsa da stabiliteyi sağlar.

Production Önerileri

Production cluster’ında bellek hatalarını sıfıra indirmek için uyguladığım ve gözlemlediğim kesin kurallar şunlardır:

  • Hard Limitlerin Belirlenmesi: gpu_mem_limit asla boş bırakılmamalıdır. Toplam VRAM kapasitesinin %80 – %85’i arasında bir değere sabitlenmelidir (Örn: 24 GB için ~20 GB). Geri kalan %15, CUDA context, NVIDIA driver işlemleri ve küçük işletim sistemi yükleri için rezerve edilmelidir.
  • Prometheus ve NVML Monitörizasyonu: Arena kullanıldığında nvidia-smi veya NVML kütüphanesi belleğin dolu olduğunu gösterir (çünkü ORT, belleği rezerve etmiştir). Gerçekte Arena’nın ne kadarının dolu olduğunu görmek için ONNX Runtime’ın iç metriklerini (Profiling) dışa aktarmak ve loglamak gerekir.
  • Dinamik Batching Limitleri: Dinamik eksenler desteklense bile, giriş boyutuna bir üst sınır (max_sequence_length) konulmalıdır. Eğer 32.000 tokenlık anomali bir istek gelirse, Arena kSameAsRequested modunda bile genişlemeye çalışır ve limitlere çarparak OOM fırlatır.
  • Memory Pattern Konfigürasyonu: ORT içindeki ORT_ENABLE_MEM_PATTERN ayarı varsayılan olarak aktiftir ve kalmalıdır. Bu ayar, bellek bloklarının fiziksel adreslerde ardışık yerleşmesini sağlar.

Sık Sorulan Sorular

ORT_ENABLE_MEM_PATTERN devre dışı bırakılırsa BFC Arena çalışmayı durdurur mu?

Hayır, BFC Arena çalışmaya devam eder ancak bellek içi planlama (memory planning) pasif duruma düşer. Bu durum, allocation sürelerini 0.01 ms seviyelerinden 0.1 ms seviyelerine çeker ve Arena’nın kendi içindeki parçalanmayı (internal fragmentation) artırır. Kapatılması önerilmez.

Çoklu GPU (Multi-GPU) topolojilerinde Arena ayarı global midir?

Hayır. CUDA Provider başlatılırken device_id parametresi ile her bir GPU için ayrı bir provider konfigürasyonu tanımlanır. Eğer 4x A100 kullanıyorsanız, providers listesine her bir device_id (0, 1, 2, 3) için bellek limitleri ve arena stratejilerini ayrı ayrı belirten dictionary objeleri eklemelisiniz.

Dinamik eksenler (dynamic axes) kullanımı BFC içerisindeki parçalanmayı tamamen engeller mi?

BFC parçalanmayı minimize eder ancak tamamen sıfırlamaz. Eğer sürekli olarak birbiriyle uyumsuz boyutlarda tensorler talep ediliyor ve aynı anda çok uzun süre hayatta kalıyorsa (long-lived tensors), Arena içinde de boşluklar oluşur. Bu senaryolarda initial_search_chunk_size değerini artırmak, parçalanmayı geciktiren etkili bir alt seviye optimizasyonudur.

TensorRT Provider kullanırken de aynı Arena ayarları geçerli mi?

Hayır. TensorRT kendi bellek havuzunu ve workspace yönetimini kullanır. Eğer ORT arkasında TensorrtExecutionProvider kullanıyorsanız, bellek yönetimi büyük oranda NVIDIA’nın kapalı kaynak kütüphanesine devredilir ve buradaki BFC parametreleri ezilir.

Sonuç

ONNX Runtime 1.17 üzerindeki CUDA Provider bellek yönetimi, varsayılan ayarlara bırakılamayacak kadar kritik bir altyapı katmanıdır. cudaErrorMemoryAllocation hatalarının çoğunun donanım yetersizliğinden değil, BFC Arena’nın büyüme stratejisindeki kNextPowerOfTwo davranışının donanım limitlerini aşmasından kaynaklandığını inceledik.

Üretim ortamındaki kod tabanınızda arena_extend_strategy parametresini kSameAsRequested olarak değiştirmek ve gpu_mem_limit ile donanıma uygun bir üst sınır belirlemek, inference altyapınızın uptime oranını doğrudan etkileyecek en maliyetsiz ve net eylem adımıdır. Doğru konfigüre edilmemiş bir bellek havuzu, binlerce dolarlık GPU kaynaklarını verimsiz bir silikon yığınına çevirebilirken, bilinçli yapılandırılmış bir BFC Arena O(1) maliyetli tensor tahsisi ile uçtan uca gecikme sürelerinde ölçülebilir bir stabilite sunar.

Bunları da beğenebilirsiniz

Bir Web Siteye Sahip Olmanız İçin 10 Neden
10 Ekim 2022

Bir Web Siteye Sahip Olmanız İçin 10 Neden

Pazarda rekabet etmek istiyorsanız, çevrimiçi bir varlığa ve daha da önemlisi size uygun olarak tasarlanmış bir web sitesine sahip olmalısınız. Belki 10 yıl önce alaka…

Devamını Oku
VictoriaMetrics’te Polimorfik İndeksleme: Yaşlanan Zaman Serisi Verilerinde Sorgu Gecikmesini Sabitleme
23 Mart 2026

VictoriaMetrics’te Polimorfik İndeksleme: Yaşlanan Zaman Serisi Verilerinde Sorgu Gecikmesini Sabitleme

VictoriaMetrics’in yaşlanan zaman serisi verileri için polimorfik indekslemeyi nasıl kullandığını keşfedin. Bu yenilikçi yaklaşım, üretim seviyesi sorgu gecikmelerini önemli ölçüde azaltarak veri erişimini optimize eder ve operasyonel verimliliği artırır.

Devamını Oku
Pulumi Automation API ile PR Bazlı İzole Test Altyapıları: State Yönetimi ve Maliyet Optimizasyonu
11 Mayıs 2026

Pulumi Automation API ile PR Bazlı İzole Test Altyapıları: State Yönetimi ve Maliyet Optimizasyonu

CI/CD pipeline’larında her Pull Request için Pulumi Automation API kullanarak izole altyapılar kurma teknikleri, S3 backend locking çözümleri ve %68 maliyet tasarrufu sağlayan yaşam döngüsü stratejileri.

Devamını Oku
AI Asistan