Nella programmazione software, sarebbe possibile avere carichi di CPU e GPU al 100%?


43

Questa è una domanda generale su un argomento che ho trovato interessante come giocatore: colli di bottiglia della CPU / GPU e programmazione. Se non sbaglio, ho capito che sia la CPU che la GPU calcolano cose, ma che in alcuni calcoli uno è migliore dell'altro a causa della differenza nell'architettura. Ad esempio, cracking hash o mining di criptovaluta sembra molto più efficiente su GPU che su CPU.

Quindi mi chiedevo: avere una GPU al 100% di carico mentre la CPU è al 50% (ad esempio) è inevitabile?

O, più precisamente: alcuni calcoli che vengono normalmente eseguiti dalla GPU possono essere eseguiti dalla CPU se il primo ha un carico del 100%, in modo che entrambi raggiungano un carico del 100%?

Ho cercato un po 'sull'argomento, ma sono tornato piuttosto a mani vuote. Penso e spero che questo abbia il suo posto in questa sottosezione e sono aperto a qualsiasi documentazione o conferenza che potresti darmi!


53
È banalmente possibile che CPU e GPU eseguano entrambe un ciclo infinito di NO-OPs contemporaneamente, il che comporterà un carico del 100%.
Jörg W Mittag,

17
Seguendo il punto di @ Jörg, l'unica cosa misurata dalla CPU% è la frazione di tempo che non viene spesa in attesa di altri processori. Il 100% può essere positivo se il programma è efficiente o negativo se il programma è inefficiente. Troppo tempo, le persone si concentrano sulla CPU% come se fosse una misura delle prestazioni - non lo è.
Mike Dunlavey,

22
L'originale Crysis ha fatto proprio questo.
CubicleSoft,

5
@MikeDunlavey hai sollevato un buon punto. Con le auto non misuriamo le loro prestazioni in base all'RPM, misuriamo la velocità.
Captain Man,

1
@ JörgWMittag: la CPU, forse. Ma i sistemi operativi e le GPU hanno fermato i risolutori di problemi per gestire loop infiniti. Vale a dire, se uno shader non si completa in un ragionevole lasso di tempo, muore e la GPU si ripristina.
Nicol Bolas,

Risposte:


62

Teoricamente sì, ma praticamente ne vale raramente la pena.

Sia le CPU che le GPU sono complete , quindi qualsiasi algoritmo che può essere calcolato da uno può essere calcolato anche dall'altro. La domanda è: quanto velocemente e quanto conveniente.

Mentre la GPU eccelle nel fare gli stessi semplici calcoli su molti punti di dati di un set di dati di grandi dimensioni, la CPU è migliore in algoritmi più complessi con molte ramificazioni. Con la maggior parte dei problemi, la differenza di prestazioni tra implementazioni di CPU e GPU è enorme. Ciò significa che utilizzare uno per prendere lavoro dall'altro quando è in stallo non porterebbe davvero a un notevole aumento delle prestazioni.

Tuttavia, il prezzo che devi pagare per questo è che devi programmare tutto due volte, una volta per la CPU e una volta per la GPU. È più del doppio del lavoro perché dovrai anche implementare la logica di commutazione e sincronizzazione. Tale logica è estremamente difficile da testare, poiché il suo comportamento dipende dal carico corrente. Aspettati molto oscuro e impossibile riprodurre i bug di questa acrobazia.


1
Hai detto che, con la maggior parte dei problemi, la differenza di prestazioni tra le implementazioni di CPU e GPU è enorme , in realtà sono abbastanza interessato fino a che punto il divario di prestazioni va. Avresti qualche numero o articolo su questo (ad esempio, sull'esempio del rendering trame 3D)? Grazie per la tua risposta e per il tuo tempo!
MadWard,

2
È possibile che si desideri aggiungere costi di prestazioni per la sincronizzazione tra CPU e GPU, quindi in genere si desidera ridurre al minimo il numero di trasferimenti tra i due. Inoltre, aggiungere ingenuamente nei rami per "non eseguire sugli elementi su cui la CPU ha già lavorato" non ti comprerebbe nulla, dal momento che i thread GPU funzionano in blocco.
Ethan,

3
@gardenhead Nulla nell'universo supporta la ricorsione illimitata, perché l'universo ha dimensioni finite e densità di informazioni finita. La "completezza turing" di un sistema è generalmente una discussione di ciò che sarebbe possibile se tali vincoli fossero rimossi.
Casuale 832,

3
Non ho dubbi sul fatto che una GPU moderna sia tecnicamente vicina alla completezza di Turing come un PC degli anni '80 ... tuttavia, se si tenta di eseguire algoritmi generali su una GPU, di solito degenererà in un processore sequenziale che non sarà più veloce di un PC degli anni '80, quindi la completezza di Turing di una GPU non è praticamente più utile della completezza di Turing di Brainfuck .
leftaroundabout

7
@leftaroundabout Le GPU moderne sono banalmente complete come qualsiasi CPU . La completezza di Turing non ha nulla a che fare con: 1) prestazioni 2) leggibilità della fonte. La CPU degli anni '80 era vicina al TC e ha tutto il resto: o erano TC o non lo erano (quest'ultima opzione era una sciocchezza).
Margaret Bloom,

36

Non è legato alla programmazione del gioco. Alcuni codici scientifici possono anche utilizzare sia la GPU che la CPU.

Con un'attenta e dolorosa programmazione, ad esempio utilizzando OpenCL o CUDA , è possibile caricare sia la GPU che la CPU quasi al 100%. Molto probabilmente dovrai scrivere diversi pezzi di codice per la GPU (il cosiddetto codice "kernel") e per la CPU, e un codice di colla noioso (in particolare per inviare nella GPU il codice del kernel compilato).

Tuttavia, il codice sarebbe complesso e probabilmente dovrai sintonizzarlo sul particolare hardware su cui stai eseguendo, in particolare perché la trasmissione dei dati tra GPU e CPU è costosa.

Ulteriori informazioni sul calcolo eterogeneo .

Vedi anche OpenACC , supportato dalle recenti versioni di GCC (ad es. GCC 6 a giugno 2016)


1
Hai ragione, i miei tag e il mio titolo erano fuorvianti, rimossi i giochi e aggiunto prestazioni / ottimizzazione. Non intendevo dire che era esclusivo dei giochi, ma è lì che l'ho notato. Ho pensato che avrebbe dovuto essere anche molto specifico per l'hardware. Grazie per la tua risposta e link!
MadWard,

3
Questo finirebbe praticamente con due algoritmi. L'ho provato una volta: intera immagine contemporaneamente per GPU e più immagini contemporaneamente per CPU (per abusare di cache di grandi dimensioni). È davvero doloroso, soprattutto da mantenere.
PTwr

11

Da un punto di vista del supercalcolo è meglio non pensare al carico in CPU / GPU in percentuale, ma piuttosto determinare quante operazioni sono necessarie al proprio problema e quindi confrontarle con le massime prestazioni del sistema.

Se si ottiene il 100% di utilizzo della CPU, ciò non significa necessariamente che tutte le prestazioni vengano fuori dal sistema. Le CPU spesso possono fare più cose contemporaneamente allo stesso tempo, ad esempio una divisione e un'aggiunta. Se puoi iniziare la divisione in anticipo, può eventualmente essere sovrapposta con l'aggiunta. Molto probabilmente la tua CPU desktop ha un'unità fuori servizio che riordinerà le dichiarazioni al fine di beneficiare di tali sovrapposizioni. O se hai il seguente programma:

if (expr1)
    expr2;
else
    expr3;

Una CPU riordinante proverà a calcolare le tre espressioni contemporaneamente e quindi a eliminare il risultato di una di esse. Questo lo rende più veloce nel complesso. Se hai qualche blocco nel tuo programma e non puoi riordinare, allora stai utilizzando meno corsie nella CPU, ma probabilmente mostrerà ancora il 100%.

Quindi hai funzioni SIMD nelle CPU che sono operazioni vettoriali. È come la luce GPGPU, nel senso che di solito hai solo quattro o otto operazioni contemporaneamente, le GPU fanno come 32 o 64. Tuttavia devi usarlo per avviare i FLOPS.

Roba come la falsa condivisione può comportare un costo di sincronizzazione pesante che di solito si presenta come caricamento del kernel in Linux. La CPU è completamente utilizzata ma non si dispone di un throughput molto utile.

Ho programmato su una macchina IBM Blue Gene / Q. Ha molti livelli gerarchici ( schematico di Blue Gene / L obsoleto ) ed è quindi difficile da programmare in modo efficiente. Dovrai utilizzare l'intera gerarchia fino a SIMD e SMT (Intel chiama HyperThreading) per ottenere prestazioni ottimali.

E poi la rete spesso ti limita. Pertanto si scopre che è più veloce nel tempo (orologio da parete) calcolare le cose su più CPU contemporaneamente invece di comunicarle sulla rete. Ciò caricherà maggiormente le CPU e renderà il programma più veloce. Ma la velocità effettiva del programma non è buona come sembra dai numeri grezzi.

Se aggiungi GPU al mix, diventerà ancora più difficile orchestrare tutto questo per ottenere prestazioni. Questa sarà una delle cose che inizierò a fare nella mia tesi di laurea magistrale in QCD tra un paio di mesi.


1

Potresti essere interessato a verificare il motore del browser Servo in fase di sviluppo presso Mozilla Research, e in particolare il suo Web Render (video) .

Mentre spostare un'attività da CPU a GPU in modo dinamico potrebbe essere poco pratico, come menzionato in altre risposte (in particolare @ Philip's), può essere pratico studiare in anticipo il carico di CPU / GPU su carichi di lavoro tipici e passare alcune attività a quelle generalmente meno caricate uno.

Nel caso di Web Render, la novità è che tradizionalmente i browser eseguono la maggior parte del loro lavoro di rendering sulla CPU (ovvero, la CPU viene utilizzata per calcolare quali oggetti visualizzare, dove tagliare, ecc ...). La GPU è normalmente migliore ... tranne per il fatto che non tutte le usecase sono banali da implementare (abbattimento parziale, ombre, ... e testo).

Una versione iniziale di Web Render si è dimostrata di grande successo nell'aumento delle prestazioni, ma non ha cercato di affrontare il problema del rendering del testo (e presentava alcune altre limitazioni). Mozilla Research sta ora lavorando a una seconda versione che intende avere meno limitazioni e in particolare per supportare il rendering del testo.

L'obiettivo, ovviamente, è scaricare il più possibile il processo di rendering sulla GPU, lasciando la CPU libera di eseguire Javascript, aggiornare il DOM e tutte le altre attività.

Quindi, sebbene non estremo come il tuo suggerimento, va nella direzione di progettare una strategia di calcolo tenendo conto sia della CPU che della GPU.


0

Con particolare attenzione ai giochi (dal momento che l'hai menzionato specificamente nel tuo post), ci sono alcuni modi per bilanciare il carico. Un esempio è "skinning", ovvero l'animazione di un modello. Per ogni fotogramma da renderizzare, devi generare le matrici di trasformazione per ogni fotogramma dell'animazione e applicarlo ai vertici del modello per trasformarlo nella posa in cui deve trovarsi. Devi anche interpolare i fotogrammi per ottenere movimenti fluidi , a meno che tu non voglia che la tua animazione assomigli al Quake originale (cioè a scatti).

In questa situazione, è possibile farlo sulla CPU e caricare i risultati sulla GPU per il rendering oppure eseguire il calcolo e il rendering sulla GPU. Credo che al giorno d'oggi sia fatto sulla GPU (nota come "skin skin dell'hardware"): ha senso farlo dato che hai calcoli relativamente semplici che devono essere eseguiti migliaia di volte e che ogni vertice può essere calcolato contemporaneamente dal risultato del vertice A non influisce sul risultato del vertice B.

In teoria, tuttavia, è possibile passare dinamicamente dal farlo sulla CPU o GPU a seconda di quanto siano sovraccarichi GPU e CPU.

Il principale blocco per fare questo attraverso tutti i calcoli è tuttavia che CPU e GPU hanno diversi punti di forza e di debolezza. I lavori massicciamente paralleli vengono eseguiti meglio sulla GPU, mentre i compiti lineari intensi con ramificazione vengono eseguiti meglio sulla CPU. Solo pochi lavori potevano realisticamente essere eseguiti su entrambi senza un grave calo delle prestazioni.

Nel complesso, il problema principale con la programmazione GPU (almeno con OpenGL e DirectX 11 e precedenti) è che hai poco controllo su come la GPU interpreta il tuo codice shader. La ramificazione all'interno di uno shader è rischiosa perché se si crea accidentalmente una dipendenza tra i calcoli, la GPU potrebbe decidere di iniziare a renderizzare i pixel uno per uno, trasformando 60 fps a 10 fps in un istante nonostante i dati effettivi da rendere identici.


0

Un esempio reale è il motore di rendering open source LuxRender , in grado di caricare contemporaneamente una CPU e una GPU. Inoltre, può caricare più GPU contemporaneamente e distribuire anche su più computer.

LuxRender utilizza OpenCL per facilitare ciò, sebbene esistano anche build senza OpenCL.

Ciò è pratico perché gli algoritmi utilizzati da LuxRender sono altamente parallelizzabili. L'algoritmo più comune utilizzato da LuxRender è il tracciato dei percorsi , in cui molti singoli percorsi luminosi possono essere calcolati indipendentemente l'uno dall'altro, una situazione ideale per il calcolo della GPU e uno che non richiede una sincronizzazione complessa tra i nodi di calcolo. Tuttavia, i limiti delle GPU (minori quantità di memoria, mancanza di supporto per alcune funzionalità di rendering complesse e generale mancanza di disponibilità per alcuni artisti) assicurano che il supporto della CPU sia ancora essenziale.


a che serve mostrare questa immagine, in che modo è pertinente alla domanda posta?
moscerino il

1
Ehh bene. Lo cancellerò. Pensavo che avrebbe dimostrato facilmente che tipo di software è. Ma forse è davvero fonte di distrazione. (Esistono molti tipi diversi di motori di rendering; questo è destinato agli alambicchi fotorealistici.)
PythonNut

0

Sì, è certamente possibile.

Qualsiasi calcolo che può fare una CPU, può fare anche una GPU e viceversa.

Ma è raro perché:

  • Complessità ingegneristica Sebbene sia possibile eseguire lo stesso codice su CPU e GPU (ad es. CUDA), i processori hanno capacità e caratteristiche prestazionali diverse. Uno è MIMD; l'altro, SIMD. Ciò che è veloce su uno è lento sull'altro (ad es. Ramificazione), quindi è necessario scrivere un codice separato per massimizzare le prestazioni.

  • Efficienza dei costi GPU sono in molti un aggregato più potente di CPU. L'idea generale delle GPU è quella di utilizzare processori più economici, più lenti, ma più numerosi per eseguire calcoli molto più velocemente rispetto alle CPU allo stesso costo. Le GPU sono più efficienti dal punto di vista dei costi di uno o due ordini di grandezza.

Se riesci a far funzionare il tuo algoritmo su GPU, ha più senso ottimizzarle e aggiungerne tutte quante ne hai bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.