Perché l'esecuzione di algoritmi con thread con il numero esatto di core della macchina è più veloce di qualsiasi altra cosa?

6

Ho fatto alcuni test di base multi-threading qui e ho notato che l'aumento di velocità quando si utilizza l'esatto è più grande di quanto mi aspettassi.

Supponevo che la velocità aumentasse linearmente fino a raggiungere il limite dei nuclei, quindi smettere di aumentare o addirittura rallentare.

Invece la velocità aumenta in modo lineare e poi JUMPS verso l'alto, ma sulla prossima quantità di thread (1+ rispetto alla macchina hanno core), "continua" da dove era prima.

Un grafico ad esempio sembrava una lunga funzione lineare, con un gigantesco picco nel mezzo, in cui avevo lo stesso numero di thread dei nuclei.

Quindi, perché?

PS: prima che qualcuno punti l'ovvio (che usando il numero di core della CPU significhi usare il massimo della CPU), so già l'ovvio, sto chiedendo del non ovvio.

EDIT: grafico realizzato in R, è il numero di "svolte" che il simulatore può eseguire per MS.

L'algoritmoèinesecuzioneattraversounaseriediagenti,quindieseguealcunicalcoliavirgolamobile,eseguealcuniconfronticonilnumerodisvoltaequindichiamaunafunzionecheeseguepiùcalcolimatematiciavirgolamobile,sultestdelgraficolafunzionenonerainlinea.

EDIT2:

Stessoprogramma,maconbuild"release".

Inoltre, vorrei notare che i "thread" qui si riferiscono ai thread worker, c'è anche un thread UI + Boss che si aggiorna alla stessa velocità di OpenGL, apparentemente questo è diventato importante su MacMini, dal momento che il grafico appare come " spento di uno "

Ecco le prestazioni di MacMini da solo, la sua CPU è un i5-2415M da 2,3 GHz (con incremento di 2,9 GHz) 2 core + HT.

EccoleprestazionidiZephyr+MacMininellaparteinferioredelgrafico,lasuaCPUèuni5-4690KconilcomportamentodiIntel,ha4core,manonhaHT.

    
posta speeder 17.12.2016 - 16:30
fonte

3 risposte

8

Alcune delle molte cose che possono o non possono essere rilevanti includono:

  • se i thread utilizzano tutto il tempo di CPU assegnato o sono costantemente bloccanti / sbloccabili (ad esempio per il file I / O, ritardi, mutex, ...)

  • quali sono le CPU / s. Un sistema NUMA (con una coppia di chip dual core) è molto diverso da "singolo chip quad-core con SMT / hyper-threading".

  • se le CPU hanno una sorta di "turbo-boost" (ad esempio, dove il single-core potrebbe ottenere un boost completo, il 2-core potrebbe ottenere un boost parziale, ecc.)

  • se i thread utilizzano una parte del tempo di tipo o risorsa, in cui la CPU potrebbe disattivarlo per risparmiare energia e dove "più thread" potrebbero mantenere tale risorsa sufficientemente occupata da impedirne la disattivazione ( ad es. l'AVX nella moderna Intel viene disattivato per risparmiare energia, quindi se viene usato temporaneamente si ottiene "il ripristino della latenza").

  • quali cache sono condivise da quali core

  • se esiste una possibilità di thrashing della cache (ad esempio, ogni core modifica la stessa riga della cache, causando il costante rimbalzo della linea cache tra i core).

  • qual è il collo di bottiglia (ad es. se è limitato dalla larghezza di banda della RAM a 4+ core, quindi lanciare più di 4 core non sarà di grande aiuto).

  • qual è il sistema operativo (o quale strategia utilizza per pianificare i thread) e la politica e priorità del thread; e se ci sono altri thread che potrebbero essere in esecuzione in background.

  • se c'è qualche tipo di IO pesante (possibilmente asincrono / non bloccante) coinvolto.

risposta data 17.12.2016 - 18:34
fonte
4

Caso interessante. Se non avessi dipendenze da altri thread, otterresti un picco al numero di cpu (o doppio con Hyper Threading) e quindi una leggera diminuzione dovuta al cambio di contesto eccessivo.

Per il momento, l'aspetto di grande salto è un mistero, potresti colpire un "punto di risonanza" in cui le richieste di callback e il cambio di contesto avvengono in una sequenza o frequenza ottimale, ma poiché lo stesso è riproducibile su altro hardware che rimane un po 'misterioso .

L'altro aspetto, tuttavia, l'aumento delle prestazioni dopo il numero di CPU, può avere molte cause note. È dovuto al modo in cui i thread di lavoro bloccano le risorse comuni (ad esempio, come interagiscono con il thread principale).

Se si dispone di un pool di thread che ottiene il lavoro assegnato dal thread principale, probabilmente non si utilizza realmente il numero dato di thread tutto il tempo poiché il thread principale potrebbe essere occupato mentre alcuni worker sono in attesa di un nuovo lavoro.

Prova a implementarlo in questo modo, dove il thread principale (o un altro thread) prima prepara pezzi di lavoro e li inserisce in una coda. Quindi lascia che i tuoi thread di lavoro eseguano il ciclo di raccolta raccogliendo un blocco, elaborandolo e rilasciandolo in un'altra coda che verrà elaborata dal thread principale (o da un altro thread). In questo modo i thread di lavoro non dovranno mai attendere il thread principale. Controlla il mio post sul blog " Completamente utilizza tutti i colli di bottiglia " dove approfondisco questa idea (con un esempio C # open source) .

Se stai aggiornando l'interfaccia utente dopo che ogni risultato è arrivato, allora quello sarà certamente un collo di bottiglia (specialmente la roba OpenGL). Vedi la mia risposta alla domanda " Perché il mio programma C # è più veloce in un profiler? " Usare un timer per rendere un frame di lo stato attuale in tal caso aumenterebbe notevolmente le tue prestazioni. Non penso che questo si applichi al tuo caso, visto che vedi un aumento con più thread.

Nessuna risposta esatta è possibile senza conoscere l'implementazione, ma spero di spingerti nella giusta direzione: -)

    
risposta data 19.12.2016 - 00:54
fonte
2

La quantità di tempo che un compito richiede è la quantità massima che impiega ogni core per fare il suo lavoro. Con 4 thread ogni thread fa 1/4 del lavoro e ogni core ha 1 thread, quindi ogni core ha la stessa quantità di lavoro. Con 5 thread, ogni thread fa 1/5 del lavoro, ma un core deve gestire 2 thread, impiegando 2/5 del tempo, che è maggiore di 1/4. Più in generale, i nuclei funzionano in modo uguale quando il numero di thread è un multiplo di 4, che il grafico riflette.

Si noti che il cambio di contesto per le attività legate alla CPU ha un effetto molto scarso sulle prestazioni finché non si raggiunge un numero di enorme (probabilmente migliaia) di thread. Questo non è certamente il tuo problema con un numero così piccolo di thread.

    
risposta data 19.12.2016 - 21:41
fonte