|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: May 2011
Messaggi: 47
|
[C/C++] Allineamento di una struttura
Ciao a tutti! In alcuni codici sorgenti ho trovato dei commenti che avvisavano riguardo all'aggiunta di strutture con un corretto allineamento, in modo tale da permettere al compilatore di non eseguire il padding per tutti i sistemi supportati.
Cosa significa il concetto di allineamento di strutture? Cosa sarebbe il padding in questo caso? Se dovessi aggiungere alcune strutture al codice per estenderlo, dovrei stare attento a come progettarle per seguire "l'allineamento"? Cercando su internet, ho trovato qualche spiegazione, ma non riesco bene a capire. Potreste gentilmente spiegarmi? Grazie in anticipo! Allineamento strutture dati (???): - http://en.wikipedia.org/wiki/Data_structure_alignment - http://msdn.microsoft.com/it-it/libr...(v=vs.80).aspx |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: May 2001
Messaggi: 12815
|
Non vorrei sbagliarmi ma è un problema relativo alla dimensione della struttura stessa, che dovrebbe essere un multiplo della parola del calcolatore (32bit o 64bit rispettivamente).
In pratica sarebbe meglio che la struttura avesse dimensione pari a multipli di 4 o 8 bytes. Questo perché, supponendo di avere una architettura a 32bit, le letture in memoria vengono effettuate a gruppi di 4 bytes... ciò significa che se hai una struttura ad esempio di 5 o 6 bytes dovrai effettuare 2 letture anziché una sola, "sprecando", per così dire, cicli di clock. Spero di non aver detto castronerie. |
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Alcuni processori (per esempio, la famiglia Motorola) "allineano" le parole su indirizzi pari/multipli di 4 a seconda della lunghezza della parola stessa. Per esempio, gli interi a 32 bit cominceranno ad un indirizzo multiplo di 4. I processori Intel in genere non hanno questo problema.
Il motivo e' (era) per problemi di performance e di semplicita' (non sono un elettronico, non sono sicuro al 100% che fossero questi i motivi). Ad ogni modo, e' chiaro che questo fa si che il bus (ammesso che sia a 32 bit) possa essere utilizzato "in pieno" per trasferire una singola parola a 32 bit, in maniera piu' semplice. E' molto importante da tenere in considerazione il fattore allineamento quando si definiscono le strutture. Per semplicita', occorre sempre pensare che partano dall'indirizzo zero. Per esempio: Codice:
struct MyStruct { char a; int b; }; Il compilatore aggiungera' dei riempitivi, piu' o meno cosi: Codice:
struct MyStruct { char a; char dummy[3]; int b; } Esistono ovviamente altri tipi di allineamento. Alcuni processori allineano su indirizzi pari, per cui sizeof(MyStruct) = 6, e cosi' via. In Visual Studio e' possibile cambiare l'allineamento mediante le proprieta' del progetto o mediante keyword speciali: Codice:
__declspec (align(8)) volatile MyVar; Questo ti permette di fare dei "giochi" interessanti: per esempio, la variabile verra' trasferita utilizzando l'intero bus a 32 bit, pertanto se utilizzi la variabile tra vari thread, potresti ben sperare che non si debba sincronizzare l'accesso (sai, sincronizzare con un semaforo l'accesso ad una singola variabile risulterebbe terribilmente lento. Questo puo' drammaticamente incrementare le prestazioni del tuo software). Sfruttando questo meccanismo, Win32 mette a disposizione le funzioni InterlockedXXX (per es: InterlockedExchange()) che ti garantiscono che la scrittura in quella variabile e' fatta in mutua esclusione SENZA DOVER SINCRONIZZARE, quindi restando in "User mode" con grande risparmio di tempo
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Aggiungo qualche informazione e considerazione.
Alcuni processori richiedono che l'accesso a determinate informazioni siano allineate secondo alcune regole, pena il sollevamento di eccezioni o il malfunzionamento. Un esempio sono i vecchi Motorola 68000/010/012, che per quantità maggiori di un byte (word, longword) richiedevano un allineamento a 16 bit. La stessa cosa capita con alcuni processori RISC, che richiedono l'allineamento a 32 bit (ad esempio i vecchi ARM). In genere il programmatore non si deve occupare di allineare le strutture in qualche modo (anche perché non saprebbe se allineare a 16, 32, 64, 128 bit, ecc.), perché è compito del compilatore. Sicuramente con delle buone conoscenze di basso livello è possibile ottimizzare l'accesso ed eventualmente anche lo spazio, organizzando opportunamente i campi delle strutture. E' comunque difficile, a causa delle differenze fra le architetture. Ad esempio ci sono architetture per cui i puntatori sono a 32 bit, e altre a 64 bit. Alcune architetture più vecchie hanno puntatori a 16 bit. Insomma, è un casino. ![]()
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Come sempre hai ragione, caro mio!
L'unica precauzione, quando possibile, e' quella di scrivere la struttura mettendo i campi piu' lunghi all'inizio, per esempio: Codice:
struct MyStruct { int a; char b; }; ![]()
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
#6 |
Member
Iscritto dal: May 2011
Messaggi: 47
|
Grazie per le risposte! Quindi, se ho capito bene, con alcuni processori l'accesso dei dati avviene prelevando una word che abbia le variabili allineate secondo uno specifico criterio, per semplificare il processo. Corretto? Come ottimizzare quindi una struttura, conoscendo l'allineamento che il compilatore andrà ad eseguire?
Codice:
#include <iostream> using namespace std; int main() { typedef struct { char a; int b; }struttura; cout << "Dimensione struttura: " << sizeof(struttura) << " bytes" << endl; } ![]() Infine (scusate se approfitto del vostro aiuto), perché la seguente struttura viene allineata in quel modo (con un allineamento di 4 bytes)? ![]() Nel primo byte viene inserita la variabile "a", il secondo byte viene riempito, mentre il terzo e il quarto byte contengono la variabile "b" e nel quinto viene collocata "c". Il software che sto estendendo deve esser eseguito solo su architetture x86-32 e x86-64 con i sistemi operativi Windows, Linux e MacOS. I compilatori che utilizzo sono Visual Studio 2010 e GCC 4.6.0. Come mi conviene creare le strutture? I compilatori supportano le istruzioni instrinseche SSE/SSE2/SSE3 per ottimizzare il programma. Nella pagina di Wikipedia che tratta l'allineamento delle strutture dati (allegato nel primo post), c'è scritto che SSE2 richiede un allineamento di 16 bytes, mentre le architetture x86 non utilizzano alcun allineamento (almeno in teoria, perché sembra proprio che utilizzino un allineamento di 4 byte). Quindi come fare per ottimizzare? Ultima modifica di Lazy Bit : 26-05-2011 alle 01:41. |
![]() |
![]() |
![]() |
#7 |
Member
Iscritto dal: May 2011
Messaggi: 47
|
(Messaggio vuoto: per errore è stato copiato due volte il messaggio precedente)
|
![]() |
![]() |
![]() |
#8 | ||||||||||
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Quote:
Quote:
Nel caso che hai esposto, aggiunge 3 byte dopo char a, in modo che int b risulti allineata a 32 bit / 4 byte. Quote:
Non sono sicuro, ma probabilmente forzando il compilatore a ottimizzare per lo spazio, la struct di cui sopra potrebbe occupare 5 byte anziché 8. Quote:
Quote:
Dopo c vengono aggiunti 3 byte, per far sì che d risulti allineata a 32 bit / 4 byte. Quote:
L'ordine in genere è il seguente: - double; - puntatori; * - long; * - int; * - float; - short; - char. Dove ho messo i 3 * è perché sono da prendere con le pinze. Potrebbe succedere, infatti, che un puntatore occupi 4 byte, mentre un long 8. Comunque in generale sono da prendere tutti con le pinze. ![]() Quote:
E le AVX prediligono i 32 byte (hanno registri a 256 bit), ma non dovrebbero avere il vincolo di accedere sempre a multipli di questa quantità. Quote:
Per il resto sono perfettamente in grado di lavorare con dati disallineati. Quote:
Il problema è: ma il compilatore lo fa? ![]() Se non lo fa, cerca di aggiungere tanti elementi all'array in modo che la sua dimensione finale sia sempre un multiplo di 16 byte. Esempio: anziché un array di 30 elementi float, allocane uno da 32 elementi. E' probabile che ci siano delle specifiche direttive per allineare (e allocare) un array opportunamente per le unità SIMD.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
||||||||||
![]() |
![]() |
![]() |
#9 |
Senior Member
Iscritto dal: Apr 2010
Città: Leuven
Messaggi: 667
|
Puo' influire il fatto che con le memorie DDR e i nuovi processori si leggono 128byte per ciclo di clock?
__________________
L'elettronica digitale non esiste, è solo elettrotecnica con interruttori piccoli! ![]() |
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Questo dipende dalla dimensione del bus. Le DDR sono a 64 bit, quindi trasferiscono 8 byte alla volta, per un burst che può arrivare 4 trasferimenti. Quindi in totale 32 byte per un burst. In dual channel il valore raddoppia, arrivando a 64 byte trasferiti.
Comunque ci sono differenze fra le memorie. Le DDR possono leggere una qualunque locazione di memoria (anche un solo byte volendo), e fermarsi sì. Con le DDR2 invece un accesso implica l'inizio di un ciclo di burst che dev'essere completato, quindi nel caso peggiore se inizi dalla prima locazione, devi completare il burst di 4 locazioni. Con le DDR3 è ancora peggio, perché lavorano con un burst completo. In ogni caso tutto ciò è utile per riempire le cache, ma questo non sempre è un vantaggio. Pensa agli accessi random a singole locazioni di memoria, ad esempio.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 21:05.