Pregunta

¿Cuál es la diferencia entre el acceso a la memoria alineados y no alineados?

I trabajar en un TMS320C64x DSP, y quiero utilizar las funciones intrínsecas (funciones de C para instrucciones de montaje) y tiene

ushort & _amem2(void *ptr);
ushort & _mem2(void *ptr);

donde _amem2 hace un Acceso alineado de 2 bytes y _mem2 que el acceso no alineado.

Cuando debo usar cuales?

¿Fue útil?

Solución

Un acceso a la memoria alineado significa que el puntero (como un número entero) es un múltiplo de un valor específico del tipo llamado la alineación. La alineación es el múltiplo dirección natural donde el tipo debe ser, o debe almacenarse (por ejemplo por razones de rendimiento) en una CPU. Por ejemplo, una CPU puede requerir que todas las cargas de dos bytes o tiendas se realiza a través de las direcciones que son múltiplos de dos. Para pequeñas tipos primitivos (menores de 4 bytes), la alineación es casi siempre el tamaño del tipo. Para estructuras, la alineación es por lo general la alineación máxima de cualquier miembro.

El compilador de C siempre pone las variables que se declaran en las direcciones que satisfacen la alineación "correcta". Así que si PTR puntos a, por ejemplo, una variable uint16_t, se alinea y se puede utilizar _amem2. Es necesario utilizar _mem2 sólo si se está accediendo, por ejemplo, una matriz de bytes embalado recibido a través de I / O, o bytes en el medio de una cadena.

Otros consejos

Muchas arquitecturas de computadora memoria de almacenamiento en "palabras" de varios bytes cada uno. Por ejemplo, la arquitectura Intel 32-bit almacena palabras de 32 bits, cada uno de 4 bytes. La memoria se aborda a nivel de un solo byte, sin embargo; por lo tanto, una dirección puede ser "alineado", lo que significa que comienza en un límite de palabra, o "no alineados", lo que significa que no lo hace.

En ciertas arquitecturas ciertas operaciones de memoria pueden ser más lenta o incluso completamente no permitido en direcciones no alineadas.

Por lo tanto, si conoce sus direcciones están alineados en las direcciones correctas, puede utilizar _amem2 (), para la velocidad. De lo contrario, se debe utilizar _mem2 ().

Las direcciones Alineados son los que son múltiplos del tamaño de acceso en cuestión.

  • se alineará acceso de 4 palabras de bytes en las direcciones que son múltiplos de 4
  • Acceso de 4 bytes de la dirección (por ejemplo) 3 será el acceso no alineado

Es muy probable que el _mem2 función que funcionará también para accesos sin alinear será menos óptima para obtener las alineaciones correctas de trabajo en su código. Esto significa que el _mem2 es probable que sea más costoso función entonces su _amem2 versión.

Por lo tanto, cuando se necesita el rendimiento (en particular cuando se sabe que la latencia de acceso es alta) sería prudente para identificar cuándo se puede utilizar el acceso alineados. La _amem2 existe para este fin -. Para darle el rendimiento cuando se conoce el acceso está alineado

Cuando se trata de 2 bytes accesos, identificación de operaciones alineadas es muy simple.
Si todas las direcciones de acceso para la operación son 'incluso' (es decir, su LSB es cero), usted tiene la alineación de 2 bytes. Esto se puede comprobar fácilmente con,

if (address & 1) // is true
    /* we have an odd address; not aligned */
else
    /* we have an even address; its aligned to 2-bytes */

Sé que esto es una vieja pregunta con una respuesta seleccionada, pero no vi a nadie a explicar la respuesta a lo que es la diferencia entre el acceso a la memoria alineados y no alineados ...

Ya se trate de DRAM o SRAM o flash u otro. Tome una SRAM como un ejemplo sencillo que se construye fuera de bits de una SRAM específica se construyen a partir de un número fijo de bits de ancho y un número fijo de filas de profundidad. digamos 32 bits de ancho y varias / muchas filas de profundidad.

si hago un poco de escritura 32 para hacer frente a 0x0000 en este SRAM, el controlador de memoria en torno a este SRAM simplemente puede hacer un solo ciclo de escritura a la fila 0.

si hago un 32 bits de escritura para hacer frente a 0x0001 en este SRAM, suponiendo que se permite, el controlador tendrá que hacer una lectura de la fila 0, modificar tres de los bytes, la preservación de uno, y escribir que a la fila 0, a continuación, lea la fila 1 modificar un byte dejando los otros tres que se encuentran y que escribir espalda. qué bytes conseguir modificado o no tiene que ver con la orden de bits para el sistema.

El primero se alinean y éste no alineado, claramente una diferencia de rendimiento más necesitan la lógica extra para poder hacer los cuatro ciclos de memoria y fusionar los carriles de bytes.

Si tuviera que leer 32 bits de dirección 0x0000 entonces una sola lectura de la fila 0, hecho. Pero leer de 0x0001 y tengo que hacer dos lecturas row0 y fila1 y dependiendo del diseño del sistema simplemente enviar esos 64 bits de vuelta al procesador, posiblemente, dos relojes de autobús en vez de uno. o el controlador de memoria tiene la lógica adicional para que los 32 bits se alinean en el bus de datos en un ciclo de bus.

16 bits lee son un poco mejor, una lectura de 0x0000, 0x0001 y 0x0002 solamente sería una lectura de row0 y podría basado en el diseño del sistema / procesador de enviar esos 32 bits de atrás y el procesador de ellas extrae o turno en el controlador de memoria de modo que aterrizan en carriles de bytes específicos por lo que el procesador no tiene que girar alrededor. Uno o el otro tiene que si no ambos. Una lectura de 0x0003 aunque es como anteriormente usted tiene que leer la fila 0 y row1 como uno de sus bytes es en cada uno y entonces o bien enviar 64 bits de la parte posterior por el procesador para extraer o el controlador de memoria combina los bits en una respuesta bus 32 bit ( suponiendo que el bus entre el controlador de procesador y la memoria es de 32 bits de ancho para estos ejemplos).

Una escritura de 16 bits, aunque siempre termina con al menos una lectura-modificación-escritura en este ejemplo SRAM, 0x0000 dirección, 0x0001 y 0x0002 lectura row0 modificar dos bytes y escribir de nuevo. dirección 0x0003 leyó dos filas modificar un byte cada uno y escribir de nuevo.

8 bits sólo tiene que leer una fila que contiene ese byte, escribe, aunque son una lectura-modificación-escritura de una fila.

El ni ARMv4 como no alineado si bien se puede desactivar la trampa y el resultado no es como era de esperar arriba,, brazos actuales no importantes permiten no alineados y darle el comportamiento anterior se puede cambiar un bit en un registro de control y luego se abortará transferencias no alineados. MIPS utiliza para no permitir, no está seguro de lo que lo hacen ahora. 86, 68 K, etc., fue permitido y el controlador de memoria puede haber tenido que hacer más trabajo.

Los diseños que no te permiten que claramente son para el rendimiento y menos lógica a lo que algunos dirían que es una carga para los programadores que otros podrían decir que hay trabajo extra en el programador o más fácil para el programador. alineado o no también se puede ver por qué puede ser mejor no intentar salvar cualquier memoria haciendo variables de 8 bits, pero seguir adelante y grabar una palabra de 32 bits o cualquiera que sea el tamaño natural de un registro o el autobús es. Puede ayudar a su rendimiento a un pequeño costo de algunos bytes. Por no mencionar el código adicional que el compilador tendría que añadir a hacer el registro de digamos 32 bits imitan una variable de 8 bits, el enmascaramiento y, a veces firmar extensión. Donde el uso de tamaños registro nativo no se requieren esas instrucciones adicionales. También puede empacar múltiples cosas en una memoria / ancho ubicación del bus y hacer un ciclo de memoria para recoger o escribirlas luego usar algunas instrucciones adicionales para manipulate entre registros no cuesta RAM y un posible lavado en el número de instrucciones.

No me acuerdo en que el compilador siempre se alineará el derecho de los datos para el objetivo, hay maneras de romper eso. Y si el destino no soporte no alineados que llegará a la falla. Los programadores no tendrían que hablar de esto si el compilador siempre lo hizo bien basa en ningún código legal que podría llegar a, no habría ninguna razón para esta pregunta a menos que fuera para el rendimiento. si no controlar la dirección de vacío ptr estar alineados o no, entonces usted tiene que utilizar el MEM2 () el acceso no alineado todo el tiempo o si tiene que hacer una then-else if en el código basado en el valor de la PTR como nik señalado. declarando nulo el compilador de C ahora no tiene manera de tratar correctamente con su alineación y que no será garantizada. si se toma un prt * Char y alimentar a estas funciones todas las apuestas están apagadas en el compilador de hacer las cosas bien, sin que añadir código extra, ya sea enterrado en la función MEM2 () o fuera de estas dos funciones. así como está escrito en su MEM2 pregunta () es la única respuesta correcta.

DRAM decir usado en el escritorio / portátil tiende a ser de 64 o 72 (con ECC) bits de ancho, y cada acceso a ellos está alineado. A pesar de que las tarjetas de memoria realmente se componen de 8 bits de ancho o de 16 o 32 bits de ancho fichas. (Esto puede estar cambiando con teléfonos / tabletas, por diversas razones) el controlador de memoria e idealmente al menos una memoria caché se sienta delante de este dram de modo que los accesos no alineadas o incluso alineados que son más pequeñas que el ancho de bus de lectura-modificación-escritura se tratan con la caché SRAM, que es mucho más rápido, y los accesos de DRAM están todos alineados accede ancho de bus completo. Si no tiene caché frente a la DRAM y el controlador está diseñado para un ancho de Accesos completos a continuación, que es el peor rendimiento, si se diseña para la iluminación de los carriles de bytes por separado (suponiendo que los chips de ancho de 8 bits), entonces usted no tiene la lectura-modificación -escribe pero un controlador más complicado. Si el caso de uso típico es con un caché (si hay uno en el diseño) entonces no puede tener sentido para tener ese trabajo adicional en el controlador para cada carril de bytes, pero tienen sólo saben cómo hacer transferencias de tamaño ancho de bus completa o múltiplos de.

_mem2 es más general. Se va a trabajar si PTR está alineado o no. _amem2 es más estricta, sino que exige que ptr estar alineado (aunque es presumiblemente ligeramente más eficiente). Así que utilice _mem2 a menos que pueda garantizar que ptr siempre alineada.

Muchos procesadores tienen restricciones de alineación de acceso a la memoria. acceso Unaligned o bien genera una interrupción excepción (por ejemplo ARM), o es sólo más lento (por ejemplo, x86).

_mem2 probablemente se implementa como ir a buscar dos bytes y usando operaciones bit a bit de cambio y o para hacer una ushort de 16 bits fuera de ellos.

_amem2 probablemente sólo lee el ushort de 16 bits desde el PTR especificado.

No sé TMS320C64x específicamente, pero supongo que requiere la alineación de 16 bits para los accesos a memoria de 16 bits. Así que usted puede utilizar <=> siempre pero con penalización en el rendimiento, y <=> cuando se puede garantizar que ptr es una dirección par.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top