Hangi tür problemler GPU hesaplamalarına kendilerini iyi borç veriyor?


84

Bu yüzden birlikte çalıştığım sorunların seri halinde en iyisi ve paralel olarak yönetilebileceği konusunda iyi bir kafaya sahibim. Fakat şu anda, CPU tabanlı hesaplamada neyin en iyi şekilde kullanıldığı ve bir GPU'ya neyin boşaltılması gerektiği hakkında pek bir fikrim yok.

Bunun temel bir soru olduğunu biliyorum, ancak aramamın çoğu, nedenini ya da belli belirsiz baş parmak kurallarını haklı çıkarmadan açıkça biri ya da diğerini savunan insanlara takılıyor . Burada daha yararlı bir cevap arıyorum.

Yanıtlar:


63

GPU donanımının iki özel gücü vardır: ham hesaplama (FLOP) ve bellek bant genişliği. En zor hesaplama problemleri bu iki kategoriden birine girer. Örneğin, yoğun doğrusal cebir (A * B = C veya Çöz [Ax = y] veya Çapraz [A], vb.), Sistem boyutuna bağlı olarak hesaplama / bellek bant genişliği spektrumunda bir yere düşer. Fast Fourier dönüşümleri (FFT) de bu kalıba yüksek toplam bant genişliği gereksinimi ile uyumludur. Diğer dönüşümlerde olduğu gibi, ızgara / ağ tabanlı algoritmalar, Monte Carlo, vb. NVIDIA SDK kod örneklerine bakarsanız, en sık karşılaşılan sorunların türünü hissedebilirsiniz.

Bence daha öğretici cevap 'GPU'lar ne tür problemler gerçekten kötü?' Sorusudur. Bu kategoriye girmeyen sorunların çoğu, bazıları diğerlerinden daha fazla çaba göstermesine rağmen, GPU'da çalıştırılabilir.

İyi eşleşmeyen problemler genellikle çok küçük veya tahmin edilemezdir. Çok küçük problemler, GPU'daki tüm iş parçacıklarını kullanmak için gereken paralellikten yoksundur ve / veya CPU üzerindeki düşük seviyeli bir önbelleğe sığabilir ve CPU performansını büyük ölçüde artırabilir. Tahmin edilemeyen problemler, verilerin GPU bellekten çekirdeğe verimli bir şekilde aktarılmasını engelleyebilecek veya SIMD paradigmasını kırarak paralelliğini azaltabilecek çok fazla anlamlı dallara sahiptir (bkz. ' Farklı çözgü '). Bu tür sorunlara örnekler:

  • Çoğu grafik algoritması (özellikle bellek alanında çok fazla öngörülemeyen)
  • Seyrek doğrusal cebir (ancak bu CPU'da da kötüdür)
  • Küçük sinyal işleme sorunları (örneğin 1000 noktadan küçük FFT'ler)
  • Ara
  • Çeşit

3
Yine de, bu "tahmin edilemez" sorunları için GPU çözümleri vardır bugünlerde değil, tipik olarak mümkün, gelecekte önem kazanabilir ederken, mümkün ve.
leftaroundabout

6
GPU performans kesicileri listesine özel olarak şubeler eklemek istiyorum. Tüm (yüzlerce) numaranızın gerçekten paralel hesaplama yapabilmesi için (SIMD'deki gibi) aynı talimatı uygulamasını istiyorsunuz. Örneğin, AMD kartlarında talimat akışlarından herhangi biri bir dalla karşılaşırsa ve uzaklaşmalıdır - tüm dalga cephesi (paralel grup) ayrılır. Eğer dalga cephesinden başka birimler birbirinden ayrılmamalı - ikinci bir geçiş yapmalıdır. Maxhutch'ın tahmin edilebilirliği ile kastettiği şey bu galiba.
Violet Zürafa,

2
@VioletGiraffe, mutlaka doğru değil. CUDA'da (yani Nvidia GPU'larda), dal ayrılması sadece en fazla 32 iş parçacığı olan mevcut çözgüyü etkiler. Farklı kodlar, aynı kodun yürütülmesine rağmen, açıkça senkronize olmadıkça senkronize değildir (örn __synchtreads(). İle ).
Pedro

1
@Pedro: Doğru, ancak genel olarak dallanma performansa zarar veriyor . Yüksek performanslı kodlar için (hangi GPU kodu değil?), Bunu hesaba katmak neredeyse şarttır.
jvriesem

21

Aritmetik yoğunluğu yüksek ve düzenli bellek erişim düzenleri yüksek olan problemler GPU'larda uygulanması kolaydır ve bunların üzerinde iyi performans gösterir.

Yüksek performanslı GPU koduna sahip olmanın temel zorluğu, bir ton çekirdeğinizin olması ve hepsinden mümkün olduğunca tam güçlülüğünden yararlanılmasını istemenizdir. Düzensiz hafıza erişim düzenlerine sahip olan veya yüksek aritmetik yoğunluğu olmayan problemler bunu zorlaştırır: ya sonuçları iletmek için uzun zaman harcıyorsunuz ya da hafızadan bir şeyler almak için çok uzun zaman harcıyorsunuz (yavaş!) Ve yeterli zaman sıkıntısı çekiyorsunuz. Elbette kodunuzdaki eşzamanlılık potansiyeli, GPU'da da iyi uygulanabilmesi için kritik öneme sahiptir.


Normal bellek erişim düzenleriyle ne demek istediğinizi belirtebilir misiniz?
Fomite

1
Maxhutch'ın cevabı benimkinden daha iyi. Düzenli erişim düzeniyle demek istediğim, belleğe zamansal ve mekansal olarak yerel olarak erişilmesidir. Yani: tekrar tekrar bellek etrafında büyük sıçramalar yapmazsınız. Aynı zamanda fark ettiğim bir paket anlaşması. Ayrıca, veri erişim düzenlerinizin derleyici tarafından bir şekilde veya programlayıcı tarafından önceden belirlenebileceği ve böylece dallanmanın (kodlardaki koşullu ifadeler) en aza indirileceği anlamına gelir.
Reid.Atcheson

15

Bu, kendi başına bir cevap olarak değil, maxhutch ve Reid.Atcheson'un diğer cevaplara eklenmesi olarak düşünülmüştür .

GPU'lardan en iyi şekilde yararlanmak için, sorununuzun yalnızca (veya büyük ölçüde) paralel olması gerekmez, aynı zamanda GPU'da yürütülecek çekirdek algoritmanın da mümkün olduğu kadar küçük olması gerekir. Gelen OpenCL açısından bu çok olarak adlandırılır çekirdek .

Daha kesin olması için, çekirdeğin GPU’nun her bir çok işlem biriminin (veya hesaplama biriminin ) kaydına sığması gerekir . Kaydın büyüklüğü GPU'ya bağlıdır.

Çekirdeğin yeterince küçük olması durumunda, sorunun ham verilerinin GPU'nun yerel belleğine (okuma: yerel bellek (OpenCL) veya bir hesaplama biriminin paylaşılan belleğine (CUDA)) uyması gerekir . Aksi halde, GPU’nun yüksek bellek bant genişliği bile, işlem elemanlarını her zaman meşgul edecek kadar hızlı değildir .
Genellikle bu hafıza yaklaşık 16 - 32 KiByte büyüktür .


Her bir işlem biriminin yerel / paylaşılan belleği, tek bir çekirdek kümesi içinde çalışan düzinelerce (?) İş parçacığı arasında paylaşılmıyor mu? Bu durumda, GPU'dan tam performans elde etmek için çalışma verilerinizi önemli ölçüde daha küçük tutmanız gerekmez mi?
Dan Neely

Bir işlem biriminin yerel / paylaşılan hafızasına yalnızca hesaplama biriminin kendisi tarafından erişilebilir ve bu nedenle yalnızca bu hesaplama biriminin işlem elemanları tarafından paylaşılır. Grafik kartının global belleğine (genellikle 1 GB) tüm işlem birimleri tarafından erişilebilir. İşleme elemanları ve yerel / paylaşılan hafıza arasındaki bant genişliği çok hızlı (> 1TB / s) ancak küresel hafızaya bant genişliği çok daha yavaş (~ 100GB / s) ve tüm hesaplama birimleri arasında paylaşılması gerekiyor.
Torbjörn

Ana GPU hafızasını sormuyordum. Ölüm hafızasının yalnızca her bir çekirdek için değil, çekirdek düzey kümesinde tahsis edildiğini düşündüm. örneğin bir nVidia GF100 / 110 gpu; 16 SM kümesinin her biri için 512 cuda çekirdeği değil. Paralel olarak maksimum 32 iş parçacığı çalıştırmak üzere tasarlanan her bir SM ile GPU performansını arttırmak, çalışma setini 1kb / thread aralığında tutmayı gerektirir.
Dan Neely,

@Torbjoern İstediğiniz tüm GPU yürütme boru hatlarını meşgul tutmaktır, GPU'lar bu iki yolu başarır: (1) en yaygın yöntem doluluk oranını arttırmaktır veya farklı olarak, eşzamanlı iş parçacıklarının sayısını artırarak (küçük çekirdeğin daha az kullanılması paylaşılan kaynaklar böylece daha aktif konulara sahip olabilirsiniz); belki de daha iyisi, (2) çekirdeğinizdeki talimat seviyesi paralelliği arttırmaktır, böylece nispeten düşük dolulukla daha büyük çekirdeğe sahip olabilirsiniz (az sayıda aktif diş). Bakınız bit.ly/Q3KdI0
fcruz

11

Muhtemelen daha önceki cevaplara daha teknik bir katkı: CUDA (yani Nvidia) GPU'lar, her biri 32 iş parçacığında bağımsız olarak çalışan bir dizi işlemci olarak tanımlanabilir. Her bir işlemcideki iplikler kilitleme adımında çalışır (uzunluktaki vektörlerle SIMD'yi düşünün).

Her ne kadar GPU'larla çalışmanın en cazip yolu, her şeyin kesinlikle adım adım yürüdüğünü iddia etmek olsa da, bu her zaman işleri yapmanın en etkili yolu değildir.

Kodunuz yoksa değil yüzlerce otomatik / güzel parallelize / parçacığı binlerce, tek tek asenkron görevleri içine yıkmak mümkün olabilir mi iyi parallelize ve sadece 32 ipler kilit aşamasında çalışan olanlarda yürütün. CUDA, sırayla işlemcilerin kendi aralarında senkronize olmalarına ve bir iş parçacığı havuzu paradigmasında görevlerin bir listesini işlemelerine olanak sağlayan muteksleri uygulamayı mümkün kılan bir dizi atom talimatı sunar . Kodunuz daha sonra çok çekirdekli bir sistemde olduğu gibi çalışır, sadece her çekirdeğin kendi 32 iş parçacığı olduğunu unutmayın.

İşte bunun nasıl çalıştığını CUDA kullanarak küçük bir örnek

/* Global index of the next available task, assume this has been set to
   zero before spawning the kernel. */
__device__ int next_task;

/* We will use this value as our mutex variable. Assume it has been set to
   zero before spawning the kernel. */
__device__ int tasks_mutex;

/* Mutex routines using atomic compare-and-set. */
__device__ inline void cuda_mutex_lock ( int *m ) {
    while ( atomicCAS( m , 0 , 1 ) != 0 );
    }
__device__ inline void cuda_mutex_unlock ( int *m ) {
    atomicExch( m , 0 );
    }

__device__ void task_do ( struct task *t ) {

    /* Do whatever needs to be done for the task t using the 32 threads of
       a single warp. */
    }

__global__ void main ( struct task *tasks , int nr_tasks ) {

    __shared__ task_id;

    /* Main task loop... */
    while ( next_task < nr_tasks ) {

        /* The first thread in this block is responsible for picking-up a task. */
        if ( threadIdx.x == 0 ) {

            /* Get a hold of the task mutex. */
            cuda_mutex_lock( &tasks_mutex );

            /* Store the next task in the shared task_id variable so that all
               threads in this warp can see it. */
            task_id = next_task;

            /* Increase the task counter. */
            next_tast += 1;

            /* Make sure those last two writes to local and global memory can
               be seen by everybody. */
            __threadfence();

            /* Unlock the task mutex. */
            cuda_mutex_unlock( &tasks_mutex );

            }

        /* As of here, all threads in this warp are back in sync, so if we
           got a valid task, perform it. */
        if ( task_id < nr_tasks )
            task_do( &tasks[ task_id ] );

        } /* main loop. */

    }

Daha sonra main<<<N,32>>>(tasks,nr_tasks)her bloğun sadece 32 iplik içerdiğinden ve böylece tek bir çözgüye sığdığından emin olmak için çekirdeği aramanız gerekir . Bu örnekte, basitlik için, görevlerin herhangi bir bağımlılığı (örneğin bir görev diğerinin sonucuna bağlı) veya çatışmalar (örneğin aynı küresel hafıza üzerinde çalışmak) olmadığını varsaydım. Bu durumda, görev seçimi biraz daha karmaşık hale gelir, ancak yapı esas itibariyle aynıdır.

Bu, elbette, yalnızca büyük bir hücre grubu üzerinde her şeyi yapmaktan daha karmaşık, ancak GPU'ların kullanılabileceği sorun türlerini önemli ölçüde genişletiyor.


2
Bu teknik olarak doğrudur, ancak yüksek bellek bant genişliğini elde etmek için yüksek paralellik gereklidir ve asenkron çekirdek aramalarının sayısında bir sınır vardır (şu anda 16). Ayrıca, bu sürümdeki zamanlama ile ilgili belgelenmemiş davranış ton da. Şu an için performansı artırmak için eşzamansız çekirdeklere güvenmemeyi öneriyorum ...
Max Hutchinson

2
Tarif ettiğim şey hepsi tek bir çekirdek çağrısında yapılabilir. Her biri tek bir çözgü içine sığacak şekilde, her biri 32 iplikten oluşan N blok yapabilirsiniz. Her blok daha sonra global bir görev listesinden bir görev alır (erişim, atomlar / muteksler kullanılarak kontrol edilir) ve bunu 32 adım adım iş parçacığı kullanarak hesaplar. Bütün bunlar tek bir çekirdek çağrısında olur. Bir kod örneği istiyorsanız, bana bildirin, ben de bir tane göndereyim.
Pedro

4

Şimdiye kadar yapılmamış bir nokta, mevcut GPU neslinin, tek duyarlıklı hesaplamalarda olduğu gibi çift duyarlıklı kayan nokta hesaplamalarında da yapmamasıdır. Hesaplamalarınızın çift hassasiyetle yapılması gerekiyorsa, çalışma süresinin tek bir hassasiyette 10 kat veya daha fazla bir oranda artmasını bekleyebilirsiniz.


Katılmıyorum istiyorum Yeni GPU'ların çoğu (veya tümü) yerel çift duyarlık desteğine sahiptir. Neredeyse tüm bu GPU'lar, muhtemelen gerekli bellek erişiminin / bant genişliğinin basit iki katına çıkması nedeniyle, tek hassasiyetin yaklaşık yarısında çalışan çift duyarlıklı hesaplamalar rapor ediyor.
Godric Seer

1
En yeni ve en iyi Nvidia Tesla kartlarının, en yüksek tekli hassasiyet performansının yarısı olan en yüksek çift hassasiyetli performans sunmakta olduğu doğru olsa da, daha yaygın Fermi mimarisi tüketici sınıfı kartlar için oran 8'e 1'dir.
Brian Borchers,

@GodricSeer SP ve DP kayan noktaların 2: 1 oranı, bant genişliği ile çok az ve bu işlemleri gerçekleştirmek için kaç tane donanım biriminin var olduğu ile ilgili hemen hemen her şeyle ilgili. Kayıt dosyasını SP ve DP için yeniden kullanmak yaygındır, bu nedenle kayan nokta ünitesi SP oplarını 2 op olarak DP opları olarak çalıştırabilir. Bu tasarımda sayısız istisna vardır, örneğin IBM Blue Gene / Q (SP mantığı yoktur ve bu nedenle SP ~ 1.05x DP'de çalışır). Bazı GPU'larda 2'den farklı oranlar var, örneğin 3 ve 5
Jeff

Bu cevabı yazdığımdan bu yana dört yıl geçti ve NVIDIA GPU'lardaki mevcut durum GeForce ve Quadro hatları için DP / SP oranının 1/32 olması. NVIDIA'nın Tesla GPU'ları çok daha güçlü çift duyarlık performansına sahip ancak aynı zamanda çok daha pahalı. Öte yandan, AMD Radeon GPU'larında aynı şekilde çift duyarlıklı performansı engellemedi.
Brian Borchers,

4

Metaforik bir bakış açısıyla gpu, tırnak yatağında yatan bir kişi olarak görülebilir. Üstte yatan kişi veridir ve her çivinin tabanında bir işlemci vardır, bu nedenle çivi aslında işlemciden belleğe işaret eden bir oktur. Tüm tırnaklar ızgara gibi düzenli bir şekildedir. Vücut iyi yayılırsa, iyi hisseder (performans iyidir), vücut sadece tırnak yatağının bazı bölgelerine dokunursa, ağrı kötüdür (kötü performans).

Bu, yukarıdaki mükemmel cevaplara tamamlayıcı bir cevap olarak alınabilir.


4

Eski soru, ancak 2014'ten gelen bu cevabın - istatistiksel yöntemlerle ilgili, ancak bir döngünün ne olduğunu bilen herkes için genelleştirilebildiğini - özellikle açıklayıcı ve bilgilendirici olduğunu düşünüyorum.


2

GPU'larda uzun gecikme süresi G / Ç vardır, bu nedenle belleği doyurmak için çok sayıda iş parçacığı kullanılmalıdır. Bir çözgü meşgul tutmak için çok iş parçacığı gerektirir. Kod yolu 10 saat ve G / Ç gecikmesi 320 saat ise, 32 çözgü doygunluğa yaklaşmalıdır. Kod yolu 5 saat ise, iş parçacığını iki katına çıkarın.

Bin çekirdekle, GPU'dan tam olarak yararlanmak için binlerce iş parçacığı arayın.

Hafıza erişimi önbellek hattıyla, genellikle 32 bayttır. Bir bayt yüklemek, 32 bayt ile karşılaştırılabilir maliyete sahiptir. Dolayısıyla, kullanım yerini artırmak için depolamayı birleştirin.

Komşu paylaşımına izin veren her çözgü için çok sayıda kayıt ve yerel RAM vardır.

Büyük setlerin yakınlık simülasyonları iyi optimize edilmelidir.

Rastgele G / Ç ve tek iş parçacığı bir ölüm sevincidir ...


Bu gerçekten büyüleyici bir sorudur; Her görev ~ 0.06sn sürdüğü zaman makul derecede basit bir görevin (havadan görüntülerde kenar tespiti) 'paralel olmak' mümkün olup olmadığını (veya çabaya değeceğini) kendi kendime tartışıyorum ancak gerçekleştirilecek ~ 1.8 milyon görev var ( yılda 6 yıllık veri değeri: görevler kesinlikle birbirinden ayrılabilir) ... yani yaklaşık 7,5 günlük bir çekirdekli hesaplama süresi. Her hesap bir GPU'da daha hızlı olsaydı ve iş nGPUcores başına [n küçük] olarak paralelleştirilebilseydi, aslında iş zamanının ~ 1 saate düşmesi olası mıydı? Olası görünmüyor.
GT.

0

Traveling Salesman gibi çok fazla kaba kuvvetle çözülebilecek bir problem düşünün. Ardından, her biri 8 spanky ekran kartı olan sunucu raflarınız olduğunu ve her bir kartın 3000 CUDA çekirdeğine sahip olduğunu hayal edin.

TÜM olası satıcının rotalarını çözün ve sonra zaman / mesafe / bazı metrikler için sıralayın. İşinizin neredeyse% 100'ünü attığınızdan emin olun, ancak kaba kuvvet bazen uygulanabilir bir çözümdür.


Bir hafta boyunca bu tür 4 sunucudan oluşan küçük bir çiftliğe girebildim ve beş gün içinde önceki 10 yıldan daha fazla dağıtılmış.net blokları yaptım.
Criggie

-1

Pek çok Mühendislik fikrini inceleyerek, bir gpu'nun görevlere, hafıza yönetimine ve tekrarlanabilir hesaplamalara odaklanmanın bir şekli olduğunu söyleyeceğim.

Matris matematiğindeki tek bir cevabı değil bir çok değeri alacağınız gibi birçok formülü yazması basit ama acı verici olabilir.

Bu, bilgisayarın değerleri ne kadar hızlı hesapladığı ve bazı formüller hesaplanan tüm değerler olmadan çalışamayacağı için formülleri çalıştırdığı için hesaplamada önemlidir (dolayısıyla yavaşlar). Bir bilgisayar, hangi programların çalıştırılacağını veya bu programlarda kullanılacak değerleri hesaplamanın sırasını çok iyi bilmiyor. Temelde kaba kuvvetleri hızlı bir şekilde zorlar ve hesaplamak için formülleri chucks'a böler ancak bugünlerde birçok program bu hesaplanan chucks'ları gerektirir ve ques (ve ques ques ve que ques ques) bekler.

Mesela, çarpışmalarda ilk olarak hesaplanması gereken bir simülasyon oyununda çarpışma hasarı, nesnelerin konumu, yeni hız? Bu ne kadar zaman almalı? Herhangi bir cpu bu yükü nasıl kaldırabilir? Ayrıca, çoğu program verileri işlemek için daha fazla zaman gerektiren çok soyuttur ve her zaman çoklu iş parçacığı için tasarlanmamıştır veya soyut programlarda bunu etkin bir şekilde yapmak için iyi bir yol yoktur.

CPU daha da iyileştikçe ve daha iyi insanlar programlama konusunda özensizleştiler ve birçok farklı bilgisayar türü için de programlamalıyız. Bir gpu, aynı anda birçok basit hesaplama yoluyla kuvveti kuvvetlendirmek için tasarlanmıştır (hafızadan bahsetmiyoruz (ikincil / ram) ve ısıtma soğutma bilgisayardaki ana şişe kanadıdır). Bir cpu aynı anda birçok soruyu yönetiyor ya da birçok yöne doğru çekiliyor, ne yapamayacağına karar veriyor. (hey, neredeyse insan)

Bir gpu hırıltılı işçi sıkıcı iş. Bir cpu tüm kaosun üstesinden gelir ve her ayrıntıyı idare edemez.

Peki ne öğreniyoruz? Bir gpu, bir kerede sıkıcı işlerin ayrıntılarını verir ve bir cpu, yapılacak çok fazla işle çok iyi odaklanamayan çok görevli bir makinedir. (Aynı anda dikkat bozukluğu ve otizmi varmış gibi).

Orada mühendislik fikirleri, tasarım, gerçeklik ve çok homurdanan çalışma var.

Ayrıldığımda, basit başladığımı, hızlıca başladığımı, hızlıca başarısız olduğunu, hızlıca başarısız olduğunu ve asla denemeyi bırakmadığımı hatırlayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.