2013-05-22 12 views
5

Come sappiamo, la CPU X86 ha un bus dati a 64 bit. La mia comprensione è che la CPU non può accedere a un indirizzo arbitrario. L'indirizzo a cui la CPU può accedere è un multiplo integrale della larghezza del suo bus di dati. Per le prestazioni, le variabili dovrebbero iniziare su (allineato a) questi indirizzi per evitare un ulteriore accesso alla memoria. Le variabili a 32 bit allineate a 4Byte saranno allineate automaticamente a 8Byte (64 bit), che corrisponde al bus dati 64 bit x86. Ma perché i compilatori allineano le variabili a 128 bit a 16Byte? Non il 8Byte Boundry?perché le variabili 128 bit devono essere allineate al limite 16Byte

Grazie

Lasciatemi rendere le cose più specifiche. I compilatori usano la lunghezza di una variabile per allinearla. Ad esempio, se una variabile ha una lunghezza di 256 bit, il Compiler lo allineerà a 32Byte. Non penso che ci sia alcun tipo di CPU con quel lungo bus dati. Inoltre, le memorie DDR comuni trasferiscono solo i dati a 64 bit una sola volta, nonostante la cache, come potrebbe una memoria riempire il più ampio bus dati della CPU? o solo tramite cache?

+3

"Come sappiamo, la CPU X86 ha un bus dati a 64 bit" - non è vero. x86 non dice nulla sulle dimensioni del bus dati. I processori moderni hanno larghezze di bus dati più grandi di così. – Mysticial

+4

Il processore non legge i dati dal bus dati, li legge dalla cache. È necessario un allineamento di 16 byte per evitare di scavalcare un limite della linea cache. –

+0

@Mysticial Penso che le più popolari CPU x86 abbiano attualmente un bus dati a 64 bit, no? – iqapple

risposta

4

Ci sono così tanti diversi modelli di processore a cui risponderò solo in termini teorici e generali.

Considerare una matrice di oggetti a 16 byte che inizia con un indirizzo costituito da un multiplo di otto byte ma non da 16 byte. Supponiamo che il processore abbia un bus a otto byte, come indicato nella domanda, anche se alcuni processori no. Tuttavia, si noti che ad un certo punto dell'array, uno degli oggetti deve essere posizionato a cavallo di un limite di pagina: la mappatura della memoria di solito funziona in pagine da 4096 byte che iniziano sui confini di 4096 byte. Con una matrice allineata a otto byte, alcuni elementi dell'array inizieranno dal byte 4088 di una pagina e proseguiranno fino al byte 7 della pagina successiva.

Quando un programma tenta di caricare l'oggetto a 16 byte che attraversa il limite di una pagina, non può più eseguire una singola mappa di memoria da virtuale a fisica. Deve fare una ricerca per i primi otto byte e un'altra ricerca per i secondi otto byte. Se l'unità di carico/archivio non è progettata per questo, allora l'istruzione richiede una gestione speciale. Il processore potrebbe interrompere il suo tentativo iniziale di eseguire l'istruzione, dividerlo in due speciali microistruzioni e rimandarle nella coda di istruzioni per l'esecuzione. Questo può ritardare l'istruzione di molti cicli del processore.

Inoltre, come osservato da Hans Passant, l'allineamento interagisce con la cache. Ogni processore ha una memoria cache ed è comune che la cache sia organizzata in "linee" a 32 o 64 byte. Se si carica un oggetto a 16 byte allineato a 16 byte e l'oggetto si trova nella cache, la cache può fornire una riga della cache che contiene i dati necessari. Se si stanno caricando oggetti a 16 byte da una matrice non allineata a 16 byte, alcuni oggetti dell'array si troveranno a cavallo di due linee di cache. Quando questi oggetti vengono caricati, è necessario recuperare due righe dalla cache. Questo potrebbe richiedere più tempo. Anche se non ci vuole più tempo per ottenere due righe, forse perché il processore è progettato per fornire due linee cache per ciclo, questo può interferire con altre cose che sta facendo un programma. Comunemente, un programma caricherà dati da più posti. Se i carichi sono efficienti, il processore potrebbe essere in grado di eseguire due in una volta. Ma se uno di questi richiede due linee di cache anziché quella normale, blocca l'esecuzione simultanea di altre operazioni di caricamento.

Inoltre, alcune istruzioni richiedono esplicitamente indirizzi allineati. Il processore potrebbe inviare queste istruzioni in modo più diretto, ignorando alcuni dei test che risolvono le operazioni senza indirizzi allineati. Quando gli indirizzi di queste istruzioni vengono risolti e si riscontrano disallineamenti, il processore deve interromperli, poiché le operazioni di correzione sono state ignorate.

+0

So che hai ragione, anche se alcuni punti sono esoterici per me. – iqapple

+0

IMO, la maggior parte di questa risposta, mentre di per sé è vera, è irrilevante per la qustion che era "Ma perché i compilatori allinea le variabili 128bit a 16Byte boundry? ". La risposta a questa domanda è semplicemente che l'hardware richiede che sia così, il compilatore non lo fa non perché è più efficiente ma perché qualsiasi altro modo non funzionerà. dici "Considera un array di oggetti di 16 byte che inizia con un indirizzo che è un multiplo di otto byte ma non di 16 byte.", beh, che semplicemente non funzionerà (perché l'hardware della CPU non lo supporta) indipendentementese la matrice attraversa il limite di una pagina. – Bull

+0

In realtà dipende da cosa la domanda intendeva per "variabile". Stavo pensando a 128 variabili come __m128i. Se si tratta di cose come 'struct foo {char x [128];};' quindi sono d'accordo con Eric. – Bull

5

Uno dei motivi è che la maggior parte delle istruzioni SSE2 su X86 richiede che i dati siano allineati a 128 bit. Questa decisione progettuale sarebbe stata presa per ragioni di prestazioni e per evitare l'hardware eccessivamente complesso (e quindi lento e grande).

+0

Penso che probabilmente è giusto. Sono bloccato qui in un ciclo cercando di capire quali compilatori allineano automaticamente il __m128i tipo che viene utilizzato per il calcolo SIMD vettorizzato –

Problemi correlati