2009-05-20 20 views
7

Tengo un montón de buffers (25 a 30 de ellos) en mi aplicación que son bastante grandes (.5mb) y se accede simulaneamente. Para empeorar las cosas, los datos en ellos generalmente solo se leen una vez, y se actualizan frecuentemente (como 30 veces por segundo). Tipo de tormenta perfecta de uso de memoria caché no óptimo.¿Es posible asignar, en el espacio de usuario, un bloque de memoria no almacenable en caché en Linux?

De todos modos, se me ocurrió que sería genial si pudiera marcar un bloque de memoria como no cacheable ... Teóricamente, esto dejaría más espacio en el caché para todo lo demás.

Entonces, ¿es una forma de obtener un bloque de memoria marcado como no cacheable en Linux?

+0

Creo que esto dañaría el rendimiento: al marcar como no almacenable en caché todas las escrituras de actualización frecuentes tendrían que ir a la memoria en lugar de escribir en el caché. – Michael

+0

La caché solo es útil en este caso si las escrituras no son secuenciales y las escrituras múltiples caen en la misma línea de caché. Si las escrituras son semi aleatorias y para el momento en que se vuelve a escribir la misma ubicación, esa ubicación se ha eliminado de la memoria caché, tiene poco sentido. –

+0

@Michael: se supone que * las actualizaciones * omiten la caché en este caso. – Tom

Respuesta

8

Cómo evitar la contaminación de las memorias caché con datos como este se cubre en What Every Programmer Should Know About Memory (PDF) - Esto está escrito desde la perspectiva del desarrollo de Red Hat tan perfecto para usted. Sin embargo, la mayor parte es multiplataforma.

Lo que quiere se llama "Acceso no temporal" y le dice al procesador que espere que el valor que está leyendo ahora no sea necesario nuevamente durante un tiempo. El procesador luego evita el almacenamiento en caché de ese valor.

Consulte la página 49 del PDF que he vinculado anteriormente. Utiliza el intel intrínseco para hacer la transmisión por el caché.

En el lado de lectura, procesadores, hasta hace poco , carecían de apoyo aparte de indicios débiles utilizando el acceso no temporal (NTA) instrucciones de recuperación previa. No hay equivalente a la combinación de escritura para lecturas, lo que es especialmente malo para memoria no almacenable como I/O mapeada en memoria. Intel, con las extensiones SSE4.1, introdujo cargas NTA . Se implementan utilizando un pequeño número de almacenamientos intermedios de carga de transmisión ; cada búfer contiene una línea de caché . La primera instrucción movntdqa para una línea de caché determinada cargará una línea de caché en un búfer, posiblemente reemplazando otra línea de caché. Accesos subsiguientes de 16 bytes alineados a la misma línea de caché será atendida desde el búfer de carga a bajo costo. A menos que haya otras razones para hacer , la línea de caché no se cargará en un caché, permitiendo así la carga de grandes cantidades de memoria sin contaminar los cachés.El compilador proporciona una intrínseco para esta instrucción:

#include <smmintrin.h> 
__m128i _mm_stream_load_si128 (__m128i *p); 

Este intrínseca debe ser utilizado varias veces, con direcciones de bloques de 16 bytes pasados ​​como el parámetro , hasta que cada línea de caché es leer. Solo entonces se debe iniciar la siguiente línea de caché . Dado que hay unos pocos streaming de leer memorias intermedias podría ser posible leer desde la memoria dos lugares al mismo tiempo

Sería ideal si al leer, los tampones se leen en orden lineal a través de la memoria. Usas lecturas de transmisión para hacerlo. Cuando desee modificarlos, los búferes se modifican en orden lineal, y puede usar escrituras en tiempo real para hacer eso si no espera volver a leerlos en el futuro desde el mismo hilo.

0

En ciertas arquitecturas de procesador, hay instrucciones especiales que se pueden usar para marcar ciertas líneas de caché como deshabilitadas. Sin embargo, estos suelen ser específicos de la arquitectura y dependen de algunas instrucciones de ensamblaje. Por lo tanto, le aconsejo que consulte la documentación de la arquitectura del procesador y descubra cómo hacerlo en el ensamblaje. Luego puede usar el ensamblaje en línea con GCC para activarlo. Sin embargo, haría que el rendimiento sea malo.

PD: Si puede, ¿le conviene pensar en una forma diferente de manejar los datos?

+0

No podrá usar instrucciones como esta del espacio de usuario ... – bdonlan

+0

Sí, en procesadores donde se trata de una instrucción privilegiada. Luego, con Linux, necesitará encontrar un lugar para colocarlo en el espacio del kernel y escribir algún tipo de función de espacio de usuario para acceder a él. – sybreon

1

Es posible que también desee examinar la afinidad del procesador para reducir la caché.

2

Los datos actualizados con frecuencia son la aplicación perfecta de caché. Como mencionó jdt, los cachés de CPU modernos son bastante grandes, y 0.5mb bien caben en el caché. Sin embargo, lo más importante es que leer, modificar, escribir en la memoria no en memoria caché es MUY lento: la lectura inicial tiene que bloquearse en la memoria, y luego la operación de escritura TAMBIÉN tiene que bloquearse en la memoria para confirmar. Y para colmo de males, la CPU podría implementar memoria sin memoria caché cargando los datos en la memoria caché, e inmediatamente invalidando la línea de la memoria caché, dejándolo en una posición que está garantizada que es peor que antes.

Antes de intentar superar la CPU de esta manera, realmente debe comparar el programa completo y ver dónde está la ralentización real. Los perfiladores modernos como valgrind cachegrind pueden medir errores de caché, por lo que puede encontrar si eso también es una fuente importante de desaceleración.

En otra nota más práctica, si está haciendo 30 RMW por segundo, en el peor de los casos es algo del orden de 1920 bytes de huella de caché. Esto es solo 1/16 del tamaño L1 de un procesador Core 2 moderno, y es probable que se pierda en el ruido general del sistema. Así que no te preocupes demasiado :)

Dicho esto, si por 'acceso simultáneo' te refieres a 'accedido por múltiples hilos simultáneamente', ten cuidado con las líneas de caché que rebotan entre las CPU. Esto no sería ayudado por la memoria RAM no almacenada en memoria caché - en todo caso sería peor, ya que los datos tendrían que viajar hasta la memoria RAM física cada vez en lugar de posiblemente pasar por el bus más rápido entre CPU, y la única manera evitarlo como un problema es minimizar la frecuencia de acceso a los datos compartidos. Para obtener más información al respecto, consulte http://www.ddj.com/hpc-high-performance-computing/217500206

+0

La lectura-modificación-escritura es muy lenta, pero esto es solo un problema si no escribe en una línea de caché completa en un corto número de instrucciones. La CPU puede detectar si se modificó una línea de caché completa y evita la lectura. –

+0

También se supone que bloquear la memoria que tiene otra CPU en la memoria caché es muy lento, por lo que tendría cuidado al afirmar que es más rápido bloquear la memoria que está en otra memoria caché que leer la misma memoria del sistema . –

Cuestiones relacionadas