assembly - ¿Las instrucciones de ARM ldrex/strex tienen que operar en datos alineados?
lock-free (3)
Restricciones de acceso exclusivas
Las siguientes restricciones se aplican a los accesos exclusivos:
• El tamaño y la duración de una escritura exclusiva con una ID determinada debe ser igual al tamaño y la duración de la lectura exclusiva anterior con la misma ID.
• La dirección de un acceso exclusivo debe estar alineada con la cantidad total de bytes en la transacción.
• La dirección para la lectura exclusiva y la escritura exclusiva debe ser idéntica.
• El campo ARID de la parte de lectura del acceso exclusivo debe coincidir con el AWID de la parte de escritura.
• Las señales de control para las porciones de lectura y escritura del acceso exclusivo deben ser idénticas.
• El número de bytes que se transferirán en una ráfaga de acceso exclusivo debe ser una potencia de 2, es decir, 1, 2, 4, 8, 16, 32, 64 o 128 bytes.
• El número máximo de bytes que se pueden transferir en una ráfaga exclusiva es 128.
• El valor de las señales ARCACHE [3: 0] o AWCACHE [3: 0] debe garantizar que el esclavo que está monitoreando el acceso exclusivo vea la transacción. Por ejemplo, un acceso exclusivo supervisado por un esclavo no debe tener un valor ARCACHE [3: 0] o AWCACHE [3: 0] que indique que la transacción es almacenable en caché.
El incumplimiento de estas restricciones causa un comportamiento impredecible.
Lo anterior es de la especificación AMBA / AXI. Encontrará que AWLOCK / ARLOCK es ignorado por algunos proveedores (lo que significa que ldrex / strex no funcionará fuera del núcleo). Tengo un código que demuestra esto, o al menos lo hará si encuentra un sistema que no admite acceso exclusivo.
https://github.com/dwelch67/raspberrypi/tree/master/extest
Dependiendo de la tarea y de lo portátil que desee, es posible que deba proporcionar soluciones swp y lrex / strex rodeadas de ifdefs y / o utilizar la gran cantidad de registros disponibles (tiempo de ejecución) para indicarle qué instrucciones son compatibles con el núcleo o no. estás corriendo. (Puede encontrar en al menos un caso ni swap ni ldrex / strex son compatibles).
En Intel, los argumentos para CMPXCHG deben estar alineados con la línea de caché (ya que Intel usa MESI para implementar CAS).
En ARM, ldrex y strex operan en reservas exclusivas granuales.
Para que quede claro, ¿significa esto entonces que en ARM los datos que se operan no tienen que estar alineados con la línea de caché?
Lo dice muy bien en el ARM Architecture Reference Manual A.3.2.1 "Acceso a datos no alineados". LDREX
y STREX
requieren alineación de palabras. Lo cual tiene sentido, porque un acceso de datos no alineado puede abarcar gránulos de reserva exclusivos.
En Intel, los argumentos para CMPXCHG NO necesitan alinearse en caché. Pruébalo, verás que funciona.
Pero está en lo cierto: en la memoria caché, Intel usa el protocolo de caché para implementar CMPXCHG. Por lo tanto, sería inteligente no colocar dos variables independientes de sincronización de alto uso en la misma línea de caché, ya que si dos procesadores se sincronizaran utilizando estas variables diferentes, las líneas de caché podrían ir y venir. Pero este es exactamente el mismo problema que para cualquier información: no hay procesadores diferentes que escriban en la misma línea de caché al mismo tiempo. Falso compartir.
Pero ciertamente no puede almacenar en caché los bloqueos alineados en línea:
struct Foo {
int data;
Lock lock;
int data_after;
};
Puedes poner diferentes bloqueos en la misma línea de caché:
struct Foo {
int data;
Lock read_lock;
int data_between;
Lock write_lock;
int data_after;
};
Dado que la lectura y la escritura tienden a ser mutuamente excluyentes, puede que no haya pérdida;
Puedes poner diferentes bloqueos en la misma línea de caché:
struct Foo {
int data;
Lock read_lock;
int data_between;
Lock write_lock;
int data_after;
};
Por cierto, en la memoria no almacenada, Intel no usa el protocolo de búsqueda de caché para operaciones atómicas como CMPXCHG. Por lo tanto, hay menos razones para almacenar en caché alinear las variables de sincronización. Pero aún puede querer: muchos subsistemas de memoria se intercalan por tamaño de caché, incluso cuando no se guardan en la memoria caché.
Y en cuanto a ARM: es más o menos lo mismo.
En un bus snoopy, o no en caché, es posible que no tenga que preocuparse demasiado por la alineación de la línea de caché.
Pero en una jerarquía de caché en clúster, tiene exactamente los mismos problemas que x86. Más aún, de hecho, es bien sabido cómo "exportar" operaciones como CMPXCHG, pero no ARM ldrexd / strexd.