2010-01-05 33 views
26

¿Puede alguien darme una explicación breve y plausible de por qué el compilador agrega relleno a las estructuras de datos para alinear sus miembros? Sé que está hecho para que la CPU pueda acceder a los datos de manera más eficiente, pero no entiendo por qué es así.¿por qué la alineación de la estructura de datos es importante para el rendimiento?

Y si esto solo está relacionado con la CPU, ¿por qué un alineamiento doble de 4 bytes en Linux y 8 bytes alineados en Windows?

+2

Hay dos cuestiones distintas pero relacionadas: la alineación y los datos de los datos de estructura de relleno –

+0

gcc alinea dobules de 8 bytes también en máquinas x86, aunque, al igual que el compilador de Microsoft. – nos

+0

¿Por qué los dobles se alinean en 8 bytes si la CPU lee datos en fragmentos de 4 bytes? no debería importar si el doble está alineado a 8 o 4 bytes, ¿no? – Mat

Respuesta

15

alineación ayuda a la CPU obtener los datos de la memoria de una manera eficiente: las transacciones de menos de fallos de cache/ras, menos de autobuses, etc.

Algunos tipos de memoria (por ejemplo, RDRAM, DRAM, etc.) es necesario tener acceso de forma estructurada manera ("palabras" alineadas y en "transacciones de ráfaga", es decir, muchas palabras a la vez) para obtener resultados eficientes. Esto se debe a muchas cosas entre las cuales:

  1. configuración de tiempo: el tiempo que le toma a los dispositivos de memoria para acceder a las posiciones de memoria
  2. arbitraje del bus sobrecarga es decir, muchos dispositivos podrían querer acceder al dispositivo de memoria

"Relleno" se utiliza para corregir la alineación de las estructuras de datos con el fin de optimizar la eficiencia de transferencia.


En otras palabras, el acceso a una estructura "mal alineada" rendirá un rendimiento general más bajo. Un buen ejemplo de este tipo de escollos: supongamos que una estructura de datos está mal alineada y requiere que la CPU/controlador de memoria realice 2 transacciones de bus (en lugar de 1) para obtener dicha estructura, por lo que el rendimiento es menor.

+0

entonces, ¿qué ocurre exactamente si, digamos que un flotador está alineado por 1 byte? – Mat

+0

@Mat: luego, dependiendo de "dónde" la "variable flotante" termina siendo asignada en la memoria, la eficiencia en el acceso a esta "variable flotante" variará. – jldupont

+0

pero ¿entiendo correctamente que el rendimiento para acceder a un flotador mal alineado no será peor que acceder a un doble alineado correctamente? – Mat

12

la CPU obtiene datos de la memoria en grupos de 4 bytes (de hecho depende del hardware sus 8 u otros valores para algunos tipos de hardware, pero vamos a seguir con 4 para mantenerlo simple), todo está bien si los datos comienzan en una dirección que es divisible por 4, la CPU va a la dirección de la memoria y carga los datos.

supongamos que los datos comienzan en una dirección no divisible por 4 digamos por simplicidad en la dirección 1, la CPU debe tomar datos de la dirección 0 y luego aplicar algún algoritmo para volcar el byte en la dirección 0, para ganar acceso a los datos reales en el byte 1. esto lleva tiempo y, por lo tanto, reduce el rendimiento. por lo tanto, es mucho más eficiente tener alineadas todas las direcciones de datos.

+1

no necesariamente en grupos de 4 bytes: esto depende en gran medida del tipo de CPU. – jldupont

+1

Esto es un poco simplificado: está bien tener un valor de tamaño BYTE en una ubicación de memoria no divisible por 4. También está bien tener un valor de tamaño PALABRA en una ubicación de memoria divisible por 2. – Niki

+3

Iba por simple; -) – Alon

3

Además de la respuesta de jldupont, algunas arquitecturas tienen instrucciones de carga y almacenamiento (aquellos utilizados para leer/escribir desde y hacia la memoria) que única operan en los límites alineados palabra - por lo que, para cargar una palabra no alineado de la memoria tomaría dos instrucciones de carga, una instrucción de cambio y luego una instrucción de máscara, ¡mucho menos eficiente!

+0

si leer un tipo que es más pequeño que 4 bytes (bool, corto, lo que sea) siempre incluye una operación de enmascaramiento y si no está alineado a 4 bytes también ¿una instrucción de cambio? – Mat

+0

@Mat: no necesariamente una "instrucción de desplazamiento": a nivel de circuito, los diseñadores de chips se usan para referirse a este tipo de operación como algo parecido a "intercambiadores de bytes". – jldupont

6

Una línea de caché es una unidad básica de almacenamiento en caché. Típicamente es 16-64 bytes o más.

Pentium IV: 64 bytes; Pentium Pro/II: 32 bytes; Pentium I: 32 bytes; 486: 16 bytes.

myrandomreader: 
    ; ... 
    ; ten instructions to generate next pseudo-random 
    ; address in ESI from previous address 
    ; ... 
    MOV EAX, DS:[ESI] ; X 
    LOOP myrandomreader 

Para memoria de lectura a caballo entre dos cachelines:

(por error de caché L1) el procesador debe esperar a que el conjunto de la línea de caché 1 a leerse desde L2-> L1 en el procesador antes de que se puede solicitar a la segunda línea de caché, causando un corto puesto de ejecución

(por L2 fallo de caché) el procesador debe esperar para dos ráfaga lee desde la memoria caché L3 (si está presente) o la memoria principal para completar en lugar de uno

puestos Procesador

  • A azar de lectura 4 byte se horcajadas sobre un límite cacheline aproximadamente 5% del tiempo durante 64 cachelines bytes, 10% para 32 los bytes y 20% para 16 los bytes.

  • Puede haber gastos generales de ejecución adicionales para algunas instrucciones sobre datos mal alineados, incluso si se encuentra dentro de una línea de caché. Esto se menciona en el sitio web de Intel para obtener algunas instrucciones de SSE.

  • Si está definiendo las estructuras de usted mismo, puede tener sentido para mirar una lista de todos los campos de datos < de 32 bits juntos en un struct por lo que los gastos generales de relleno se reduce o, alternativamente, un análisis sobre la mejor recurrir embalaje dentro o fuera para una estructura particular.

  • En MIPS y en muchas otras plataformas, no puede elegir y debe alinearse: ¡excepción del núcleo si no lo hace!

  • La alineación también puede importarle especialmente si está realizando E/S en el bus o usando operaciones atómicas como incremento/disminución atómica o si desea poder transferir su código a un dispositivo que no sea Intel.

  • En el código Intel (!), Una práctica común es definir un conjunto de estructuras empaquetadas para red y disco, y otro conjunto acolchado para memoria y tener rutinas para convertir datos entre estos formatos (también considere "endianness" para los formatos de disco y red).

Cuestiones relacionadas