CUDA Kullanarak Sıralama Algoritması
(ashwanirathee.com)- CUDA kullanarak paralel hesaplama üzerinden sıralama algoritmasının performansını iyileştirmenin yöntemi
- Temel bir merge sort'u CUDA ile uygulayarak performans iyileştirme olasılığını inceleme
Temel özyinelemeli merge sort (CPU uygulaması)
- Diziyi iki alt diziye bölüp her birini sıraladıktan sonra birleştiren bir sıralama algoritması
- Dizi özyinelemeli olarak bölünür, boyut 1 olduğunda birleştirme işlemi gerçekleştirilir
- Uygulamayla ilgili başlıca noktalar
uint8_tkullanımı → küçük değerlerle (0~255) bellek kullanımını en aza indirmelong longkullanımı → büyük dizileri (en fazla 10¹⁸) işleyebilme- Performans karşılaştırması için sonuçlar
std::sortile doğrulanır - Zaman karmaşıklığı: ortalama O(n log n)
- Alan karmaşıklığı: O(n)
CUDA'da temel özyinelemeli merge sort
- CPU uygulamasıyla aynı deseni izler
- Birleştirme işlemi CUDA'da paralel çalışacak şekilde uygulanır
- Uygulamayla ilgili başlıca noktalar
cudaMalloc,cudaMemcpy,cudaFreekullanımı → GPU belleği ayırma ve veri aktarımımerge<<<1, 1>>>(...)→ birleştirme işlemini paralel çalıştırmacudaDeviceSynchronize()→ birleştirme tamamlanana kadar senkronizasyon- Performans sorunu → CUDA özyinelemeyi verimsiz işlediği için yinelemeli bir yaklaşım gerekir
CPU ve GPU uygulamalarının karşılaştırması
- Özyinelemeli çağrılar CPU'da çalıştığı için performans düşüşü oluşur
- CUDA'da özyinelemeli çağrılar yığın boyutu sorunları ve kernel çalıştırma ek yükü oluşturur
- Performans iyileştirme yöntemi: yinelemeli (bottom-up) yaklaşıma geçiş gerekli
Bottom-up yinelemeli merge sort (CPU uygulaması)
- Küçük alt dizilerden başlayarak kademeli birleştirme → CUDA'da daha verimli
- Birleştirilen dizi boyutu 1, 2, 4, 8, … şeklinde artırılarak birleştirme yapılır
- Başlıca kod yapısı
MERGE_SORT(arr, temp, start, end) FOR sub_size ← 1 TO end STEP 2 × sub_size DO FOR left ← 0 TO end STEP 2 × sub_size DO mid ← MIN(left + sub_size - 1, end) right ← MIN(left + 2 * sub_size - 1, end) MERGE(arr, temp, left, mid, right) ENDFOR ENDFOR END MERGE_SORT - Uygulamayla ilgili başlıca noktalar
- Dizi boyutu 2'nin katı olmadığında indeksleri clamp ederek sorun çözülür
- Döngüler üzerinden birleştirme işlemi gerçekleştirilir
- Performans iyileştirme potansiyeli yüksektir
Bottom-up yinelemeli merge sort (CUDA uygulaması)
- Yinelemeli merge sort paralel çalıştırılarak performans iyileştirilir
- Birleştirme işini paralel yürütmek için thread ve block sayıları hesaplanıp çalıştırılır
- Başlıca kod yapısı
void mergeSort(uint8_t* arr, uint8_t* temp, long long n) { bool flipflop = true; long long size; for (size = 1; size < n; size *= 2) { numThreads = max(n / (2 * size), (long long)1); gridSize = (numThreads + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; mergeKernel<<<gridSize, THREADS_PER_BLOCK>>>(flipflop ? arr : temp, flipflop ? temp : arr, size, n); CUDA_CHECK(cudaGetLastError()); CUDA_CHECK(cudaDeviceSynchronize()); flipflop = !flipflop; } if (!flipflop) CUDA_CHECK(cudaMemcpy(arr, temp, n * sizeof(uint8_t), cudaMemcpyDeviceToDevice)); } - Başlıca noktalar
flipflop→ birleştirme sonucunun kaydedildiği konumu değiştirmegridSize,THREADS_PER_BLOCK→ birleştirme işini paralelleştirmemergeKernel→ her thread'e benzersiz bir birleştirme işi atama- Thread ve block indeks hesaplamalarıyla indeks yönetimi
Performans sonuçları
- Bottom-up merge sort (CUDA) → performans iyileşmesi nettir
- Küçük diziler → CPU daha hızlı
- Büyük diziler → CUDA performans avantajı sağlar
thrust::sort→ büyük dizilerde GPU performansı güçlü- CUDA'nın performans iyileştirmesi veri aktarım ek yüküyle sınırlanır
Sonuç ve gelecek çalışmalar
- CUDA tabanlı merge sort'ta performans iyileştirmesi başarıyla sağlandı
- Öğrenilen başlıca noktalar:
- CUDA'nın paralel işleme kavramları ve performans tuning stratejileri öğrenildi
- Yinelemeli merge sort → CUDA'da özyinelemeli yaklaşımdan daha etkilidir
- Thread senkronizasyonu, bellek aktarımı gibi CUDA'ya özgü performans darboğazları keşfedildi
- Gelecekteki iyileştirme çalışmaları:
- CPU-GPU arasında iş bölümünün ayrılması ve optimize edilmesi
- Daha büyük diziler için performans testleri
thrust::sortile kullanıcı uygulaması kodunun birleştirilmesi- Paylaşılan bellek kullanımıyla performans optimizasyonu
2 yorum
CUDA'da radix sort ile uygulanmış gibi görünüyor; ben de referanstakini birebir uygulama deneyimi yaşamıştım.
Hacker News görüşleri
Bu, GPU'da hızlı sıralama yapmanın yolu değil. CUDA'daki en hızlı algoritma Onesweep; GPU paralelliğinden yararlanmak ve sınırlamaların üstesinden gelmek için karmaşık teknikler kullanıyor
Diğer görüşlerde de belirtildiği gibi bu algoritma uygun değil. Onesweep gibi algoritmalar etkileyici, ancak anlaşılması zor
Eğlenceli bir oyuncak problem olarak ele almak için iyi. Thread ayarlama seçenekleri kullanılırsa performans artışı olabilir
Futhark dili, bu tür algoritmaların GPU'da daha rahat kullanılmasını sağlıyor
Üniversite yıllarında CUDA'da bitonic sort gerçekleştirdiğim küçük bir proje aklıma geldi
GPU thread indexing kavramını açıklayan notlar iyi
Hızlı bir radix sort implementasyonunu beğendim
Unity ile birlikte kullanmayı denedim ama veri aktarımı darboğazını aşamadım
GPU'da sıralamanın değerli olması için büyük diziler gerekiyor
Zaman kazandırması için özetle: birisi GPU'da bir sıralama algoritması yazmış ama yavaştı