In che modo i programmi scritti in lingue più elevate sfruttano "l'esecuzione dinamica" presente nei nuovi processori Intel?

4

Ho appreso che i nuovi processori Intel possono eseguire "l'esecuzione dinamica" (ovvero l'esecuzione di istruzioni non in ordine). Come si avvantaggiano i programmi scritti in un linguaggio di alto livello? Il compilatore modifica il codice in modo che possa trarne beneficio?

Ogni anno emergono nuove architetture di processore, ma linguaggi come c, c ++ rimangono uguali. In che modo i programmi scritti in queste lingue traggono vantaggio da questa nuova tecnologia?

    
posta user117953 04.03.2017 - 17:36
fonte

4 risposte

4

Il tuo programma non ha bisogno di fare nulla in particolare per trarre vantaggio dall'esecuzione fuori ordine. Il processore eseguirà solo più istruzioni per ciclo perché può avviare un'altra istruzione molto prima che sia terminata quella precedente.

Naturalmente, per ottimizzare i compilatori è necessario sapere come funziona il processore per produrre codice ottimale. Con l'esecuzione fuori servizio, a volte significa che non è più necessario prestare la massima attenzione. Prendi una sequenza di istruzioni x = a + b + c; y = d + e + f;

Senza l'esecuzione di OoO, dovresti compilarlo a tmp1 = a + b; tmp2 = d + e; x = tmp1 + c; y = tmp2 + f; perché in questo modo le aggiunte possono essere fatte in parallelo. Con l'esecuzione fuori servizio vengono comunque eseguiti in parallelo, quindi il compilatore non deve preoccuparsi.

D'altro canto, poiché puoi fare più operazioni per ciclo, il tuo codice potrebbe ora essere limitato dalla latenza. Migliorare una cosa che limita le prestazioni significa che raggiungi limiti altrove. Quindi il tuo compilatore potrebbe provare a ridurre la latenza ora, cosa che non avrebbe fatto senza l'esecuzione di OoO.

    
risposta data 04.03.2017 - 18:09
fonte
3

Altre risposte sono buone, ma lasciatemi solo evidenziare una cosa: ogni ingegnere umano può ottimizzare il proprio "codice", anche se il loro codice è in sequenza nel processore.

Quindi l'esecuzione out-of-order è ciò che l'ingegnere della CPU implementa perché è ciò di cui è responsabile.

Lo sviluppatore del sistema operativo fa quello che può per sovrapporre I / O, cache file, ecc. perché è la loro responsabilità.

Costruttori di compilatori e librerie - stessa idea.

Ora prendi i programmatori di applicazioni. Lo vedi asserito tutto il tempo sullo scambio di stack che gli ottimizzatori del compilatore sono così buoni (che è vero) che non devi preoccuparti di ottimizzare il codice dell'applicazione (che è falso). Piuttosto, un programmatore di applicazioni dovrebbe, prima di tutto, fare affidamento sulla facilità di manutenzione, ma poi , trova le funzioni che necessitano di memoizing, trova l'allocazione di memoria inutile, trova le chiamate in biblioteca inutili che, in fondo, sparano I / O. Queste cose e molte altre sono la responsabilità del programmatore dell'applicazione. Nessuna quantità di ottimizzazione da parte della CPU, del sistema operativo, delle librerie o dei compilatori, li farà per te e risparmiano "enormi" multipli in termini di prestazioni. Questo è il mio metodo go-to.

    
risposta data 06.03.2017 - 02:19
fonte
2

La risposta cinica: loro no! Storicamente, è Intel che ha studiato centinaia di file eseguibili per trovare le sequenze di istruzioni comuni, quindi ha fatto in modo che i processori eseguissero queste sequenze prima ancora di aver controllato se l'intera sequenza fosse davvero lì. La parte che richiede più tempo è l'inizio di una funzione che prepara il frame dello stack per le variabili locali. Per C e C ++, la pulizia viene eseguita immediatamente dopo l'istruzione "call", per pascal, viene eseguita alla fine della funzione stessa. Alcuni compilatori cercano di aiutare il processore alternando i registri invece di usare EAX "sistematicamente.Altri trucchi usati da alcuni compilatori sono di interlacciare istruzioni in virgola mobile con numeri interi.Il chip 8087 era un chip esterno, completamente autonomo e tutti i processori x86 implementano ancora il operazione a virgola mobile interna come se si trattasse di un chip separato, quindi, sia integer che in virgola mobile procedono in parallelo.

Un compilatore progettato in modo intelligente può sostituire il costoso salto condizionato implicito da "if" con operazioni aritmetiche che non richiedono una modifica dell'indirizzo del puntatore di istruzioni. Il costo di cambiare PC è drammatico: costringe il processore a scartare tutte le istruzioni nella pipeline, annulla qualsiasi modifica calcolata provvisoriamente quando si eseguono in anticipo tante istruzioni che seguono il ramo.

Il compilatore, sfortunatamente, non può intuire l'intento dei programmatori che cercano di imbrogliare il sistema operativo, ad esempio per ottenere il proprio thread con la priorità più alta (danneggiando il delicato equilibrio della priorità sintonizzata), o provare ad aggiornare una GUI elemento migliaia di volte al secondo (quando l'aggiornamento dello schermo è di 60 Hz), invia richieste a un server un milione di volte al secondo o viola qualsiasi altra semplice regola di buona ingegneria.

    
risposta data 05.03.2017 - 13:06
fonte
1

(non so cosa significhi esecuzione dinamica , ma ho familiarità con l'idea di esecuzione fuori-ordinazione )

Mentre il x86-64 set di istruzioni è (quasi) uguale tra processori recentissimi e quelli di cinque anni fa (forse con l'eccezione delle estensioni di istruzioni vettoriali come AVX-512 ), le regole di ottimizzazione sono cambiate.

In altre parole, un codice macchina programma ( eseguibile o libreria ) generato e ottimizzato per un i3770 da cinque anni fa non sarà il miglior codice ottimizzato per un recente AMD Ryzen (ma sarà in grado di girare su quella ricompensa Ryzen 1800x senza , dal momento che usa lo stesso set di istruzioni ). Quindi il codice macchina ottimizzato per Ryzen non è il massimo per i3770 e viceversa.

Ma i compilatori lo sanno e possono generare il codice ottimizzato per un particolare marchio di CPU. Quindi generano un codice su misura per caratteristiche specifiche del tuo particolare processore (ad es. Dimensioni e organizzazione della cache della CPU , configurazione e comportamento del suo predittore di ramo , esecuzione fuori-ordinazione & pipeline , etc etc etc ...)

Quindi è necessario aggiornare il compilatore (potrebbe essere importante ottenere una versione recente ) e passare ad esso le opzioni appropriate.

Per GCC , leggi ottimizzazione delle opzioni sezione e anche la sezione x86 .

Raccomando (per dritto , non incrociato , compilazione) compilazione con gcc -Wall -O2 -march=native sulla stessa macchina di quella che esegue il codice. Se vuoi compilare un binario in grado di funzionare su diversi marchi, devi essere più attento.

BTW, alcuni compilatori (incluso GCC ...) forniscono extra builtins (e anche builtin specifici x86 ) per sfruttare le funzionalità del processore non visibili al codice C; ad esempio __builtin_prefetch (per esplicito prefetching della cache della CPU), ma vedi questo che suggerisce di evitare di usarli in generale (perché i compilatori sono spesso - ma non sempre - ottimizzano abbastanza bene).

In pratica, i compilatori recenti fanno un buon lavoro sulle ottimizzazioni, quindi non penso che valga la pena di aggiustare il codice manualmente per ottimizzarlo ancora di più, ma YMMV. Potrebbe valere la pena di ricompilare il codice sorgente (o alcuni software libero ) durante l'aggiornamento del processore, ma di solito vincerai solo poche percentuali di rendimento.

(IMHO, cache località conta un lotto di più, poiché un importante -L3- cache miss impiega tutto il tempo necessario per eseguire più di un centinaio di istruzioni macchina, ad esempio preferisce i vettori alle liste collegate

    
risposta data 04.03.2017 - 17:44
fonte

Leggi altre domande sui tag