lunes, 22 de noviembre de 2010

Como funcionan las transacciones en el bus frontal (FSB) (aka Getting Physical With Memory)

                           Nota previa:
Esta es la cuarta entrega de las traducciones de los trabajos de Duarte. Versa sobre la estructura de una transacción en el bus frontal de procesador (con la memoria RAM, se entiende) y pueden encontrar el original aquí. En este caso la traducción la hizo Jorge y yo hice algunas correcciones menores (de estilo mas que nada). Hay un término impreciso en el segundo párrafo que no pudimos procesar completamente, aceptamos sugerencias. Como todos los trabajos de Duarte, creo que tiene un valor especial para alumnos de ingenierías relativas, para lo que llegan nuevos pueden encontrar las tres primeras traducciones aquí, aquí y aquí. Dicho esto, los dejo con Duarte, provecho y hasta el próximo.


Cuando tratas de entender sistemas complejos, frecuentemente aprendes mucho descomponiendo abstracciones y analizándolas en sus niveles más bajos. En ese espíritu, le echaremos una ojeada a la memoria y a los puertos de entrada/salida (I/O) en su nivel más simple y fundamental: la interfaz entre el procesador y el bus. Estos detalles son la base de tópicos de niveles superiores como la sincronización de hilos y la necesidad del Core i7. También, dado que soy un programador, ignoro cosas de las que se ocupan la gente de EE (Electrical Engineering). Aquí esta de nuevo nuestro amigo el Core 2:



Un procesador de 2 núcleos (Core 2) tiene 775 pines, cerca de la mitad de los cuales solo proveen energía y no transportan datos. Una vez que agrupas los pines por funcionalidad, la interfaz física del procesador es sorprendentemente simple. El diagrama muestra los pines involucrados en operaciones de memoria o puertos de I/O: líneas de dirección, pines de datos y pines de interrupciones. Estas operaciones tienen lugar en el contexto de las transacciónes del bus frontal (FSB). Las transacciónes en el FSB comprenden 5 fases: arbitraje, solicitudes, registro (snoop en el original vean la aclaración al final(1)), respuesta y datos. A través de estas fases, los componentes de FSB, que son llamados agentes, juegan diferentes roles. Normalmente estos agentes son los procesadores más el puente norte (northbridge en el original y en lo adelante).
En este post solo atenderemos la fase de solicitud, en la que dos paquetes son emitidos por el agente solicitante, el cual normalmente es el procesador. Aquí mostramos los bits más jugosos del primer paquete, emitidos por los pines de direcciones y de solicitudes



Las líneas de dirección suministran la dirección inicial de memoria física para la transacción. Tenemos 33 bits, pero son interpretados como los bits 35-3 de una dirección en la que los bits 2-0 son igual a cero, de modo que tenemos una dirección de 36 bits, alíneados en 8 bytes, para un total de 64 Gb de memoria física direccionable. Esto ha sido así desde el Pentium Pro. Los pines de solicitud especifican que tipo de transacción se iniciará; para solicitudes de I/O (E/S) los pines de dirección especifican un puerto de (entrada/salida) en vez de una dirección de memoria. Luego de que sale el primer paquete, los mismos pines transmiten un segundo paquete, en el siguiente ciclo de reloj del bus 
 
Las señales de atributos son interesantes: reflejan los 5 tipos de comportamientos de cacheo de memoria disponibles en procesadores Intel. Al poner esta información en el FSB, el agente solicitante le informa al resto de los procesadores como afectará esta transacción sus cachés, y como el controlador de memoria (Northbridge) deberá comportarse. El procesador determina el tipo de una región dada de memoria principalmente observando las tablas de páginas, las cuales son mantenidas por el kernel.  
 
Típicamente, los kernels tratan toda la memoria RAM como memoria write-back (2) porque brinda el mejor rendimiento. En el modo write-back, la unidad de acceso a memoria es la línea de caché, 64 bytes en un Core 2. Si un programa lee un byte único en memoria, el procesador carga la línea de caché completa que contiene el byte en los niveles 1 y 2 de caché (L1 y L2). Cuando un programa escribe en memoria el procesador solo modifica la línea en la caché, pero no actualiza la memoria principal. más tarde, cuando es necesario poner la línea modificada en el bus, la línea de caché íntegra es escrita de una vez. De modo que la mayoría de las solicitudes tienen un 11 en el campo de longuitud para 64 bytes, He aquí un ejemplo de lectura en el que los datos no estan en la caché:



Una parte del rango de memoria en una computadora Intel es mapeada a dispositivos como unidades de discos duros y tarjetas de red en lugar de memoria RAM. Esto le permita a los drivers comunicarse con sus dispositivos escribiendo hacia o leyendo desde la memoria. El kernel marca estas áreas de memoria como "no-cacheables" en las tablas de páginas. Los accesos a regiones de memoria no-cacheable son reproducidos en el bus exactamente como son solicitados por un programa o un driver. De esta forma es posible leer o escribir bytes simples, words y así. Esto es ejecutado mediante la máscara de habilitacion de byte en el paquete B arriba.

Los fundamentos discutidos aquí tienen muchas implicaciones. Por ejemplo:
1.- Las aplicaciones sensibles al rendimiento deben tratar de empaquetar los datos accesados juntos en la misma línea de caché. Una vez que la línea es cargada, las lecturas subsecuentes son mucho más rápidas y se evitan los accesos extras a memoria RAM.
2.- A cualquier acceso a memoria que caiga dentro de una línea de caché única se le garantiza la atomicidad (es decir que es tratado como un ente monolítico)(asumida la memoria write-back). Este tipo de accesos es servido por la caché de nivel 1 (L1) del procesador y el dato es leído o escrito completo de una vez; el proceso no puede ser interrumpido por otros procesadores o hilos. En particular, las operaciones de 32 y 64 bits que no excedan el límite de la línea de caché son atómicas. 
3.- El bus frontal es compartido por todos los agentes, quienes deben arbitrar su propiedad (referido a pertenencia no a característica) antes de iniciar una transacción. más que eso, todos los agentes deben escuchar a todas las transacciones en aras de mantener la coherencia de la caché. De esta manera la posesión del bus se convierte en un problema severo a medida que se adicionan más nucleos y más procesadores a los ordenadores Intel. El core i7 resuelve este problema enlazando los procesadores directamente a la memoria y comunicándose con esta directamente (punto a punto en el original) y no por difusión 
Estos son los aspectos más destacados respecto a las solicitudes de memoria física; el bus volverá a aparecer en relación con los bloqueos (se refiere a la acción de bloquearse de un hilo en espera de un suceso), el multi-hilo y la coherencia de caché. La primera vez que ví al descripción de un paquete en el FSB proferí un gran "Ahhhh!" espero que a alguien más ahí afuera le cause el mismo efecto. En el próximo post descenderemos nuevamente la escalera de las abstracciones para echar una ojeada a la memoria virtual.

(1)- Esta es la palabra más díficil del post entero, infiero que "snoop" es la acción del procesador de esperar el resultado de una acción previa, antes de continuar el procesamiento, a este nivel hay cosas que no entiendo a la primera (ni a la segunda a veces :-) ), de todas maneras aceptamos sugerencias y queda abierta a modificación. 

(2)- El write-back es un método de cacheo en el cual las modificaciones a los datos no son copiadas a la fuente u origen de caché hasta que no es absolutamente necesario.

(3)- "qword" se refiere a quad (es decir cuádruple) word, es decir 4 palabras (8 bytes)


(4)- La cache "write-through" es un tipo de memoria en la que todas las modificaciones se sincronizan inmediatamente con la fuente (es aproximadamente lo contrario de la write-back)