ARQUITECTURA DE SISTEMAS PARALELOS. 3º INGENIERIA TECNICA EN INFORMATICA DE SISTEMAS. FEBRERO, 2004. SOLUCIONES C1. (2 puntos) El PowerPC 620 es un procesador de 64 bits con dos caches internos separados (datos e instrucciones) de 32KB cada uno, asociativos por conjuntos (vías). El tamaño de línea es de 64 bytes. El tamaño de página es de 4KB, y se desea que el acceso a cache se realice sólo con la parte de las direcciones que se corresponde con el desplazamiento dentro de la página. Se pide: • ¿Cuál es el grado de asociatividad (número de vías) de los caches internos? • ¿Qué ventaja puede tener el hecho de que el acceso a cache se realice sólo con el desplazamiento dentro de la página? Respuesta: Se desea que la búsqueda en cache pueda realizarse sólo con los bits que se corresponden con el desplazamiento dentro de la página (12, pues 212=4KB). Puesto que el tamaño de línea es 64 bytes (26), quedan 12-6=6 bits de índice, lo que nos da un total de 26=64 conjuntos, formados por n vías, cada una con 64 bytes. Habrá un total de 32KB/(64*64) ó 215/212=23=8 vías. Un razonamiento más sencillo es que si se quiere acceder a cache sólo con log2(tamaño_página) entonces cada vía debe ser del tamaño de una página, luego el número de vías será 32KB/4KB=8. Pero, cuidado, esto NO quiere decir que en cada vía hay una página guardada. La ventaja es obvia: permite comenzar la búsqueda en cache sin necesidad de transformar primero la dirección virtual en dirección física. Es decir, mientras se accede a la TLB/Tabla de Páginas con la parte alta de la dirección virtual para encontrar el marco de memoria física, simultáneamente accedemos a cache. Cuando tengamos la dirección física completa (salvo fallo de página), sólo quedará comparar las etiquetas. C2. (1 punto) Para recibir datos de un periférico (con una tasa media de 100 bytes por segundo) se pueden usar dos métodos: • Hacer un muestreo (polling) cada milisegundo, muestreo que ocupa la CPU por un total de 1µs (microseg.) • Usar interrupciones, con un tiempo de respuesta (desde que se activa la señal de interrupción al llegar un byte hasta que se entra en la rutina de servicio) de 1µs. El tiempo de leer un byte se supone despreciable. ¿Qué método es preferible desde el punto de vista del uso de CPU?¿Cuál debe ser el periodo de muestreo para que el método preferible sea otro? Respuesta: El periférico envía 1 byte cada 10ms. Puesto que el muestreo (polling) se realiza cada ms, gastamos 1µs cada ms (haya dato o no), mientras que con interrupciones (que sólo se activan cada vez que llega un byte) gastamos 1µs cada 10ms, diez veces menos. Por tanto es preferible en este caso usar interrupciones. Incluso si se reduce la frecuencia de muestreo a 1 cada 10ms, el caso óptimo, como mucho igualamos a las interrupciones debido al hecho de que el costo del muestreo es el mismo que el de la rutina de servicio. Sin embargo, téngase en cuenta que según otros parámetros el razonamiento puede ser distinto. Por ejemplo, con interrupciones el tiempo de respuesta es casi inmediato, mientras que el muestreo puede no coincidir con el momento justo de la llegada del dato (se usan buffers), por lo que desde el punto de vista de cada dato aislado las interrupciones seguirían siendo más rápidas. En resumen, sólo cuando el tiempo de respuesta a interrupciones sea mayor que el de muestreo y el periodo de muestreo se ajuste suficientemente al tráfico de datos será preferible usar muestreo desde el punto de vista de uso de la CPU. C3. (1 punto) Explique brevemente cuál es la diferencia fundamental entre una topología de switches centralizados y una de swicthes distribuidos. Ponga ejemplos de ambos tipos. ¿Cuál será el ancho de banda de bisección de una red hipercubo de 16 nodos con todos los enlaces de fibra óptica de 1000Mbits/seg? ¿Cuánto valdrá la latencia de transporte entre dos computadores físicamente conectados si la distancia entre ellos es de 100m y el tamaño medio del mensaje es 125 bytes? Respuesta: Ancho de banda de bisección = 8 * 1000Mbits/seg = 8000Mbits/seg Latencia_transporte = Tiempo_vuelo + Tiempo_transmisión = Distancia/Velocidad + Tamaño/Ancho de banda = 100m / (2/3 * 300000Km/s) + 125bytes / 1000Mbits/seg = 0,1 * 106 / (2/3 *300000) µs + 125*8 / 1000 µs = 0,5µs + 1µs = 1,5µs PROBLEMAS: P1. (3 puntos) Escriba una función llamable desde C con el siguiente prototipo (modelo SMALL): long funcion (long num, int x); La función debe devolver el número num despreciando los x bits menos significativos. Se supone que x<32. La función debe devolver 0 si num es demasiado pequeño. Compare ahora un programa que llame a esta función desde main con otro idéntico pero que escriba el código de la función como parte de la propia main. ¿Qué instrucciones se ejecutan de más en el caso de llamar a la función? (Debe explícitamente incluir el paso de parámetros, la llamada y el retorno, etc.). Respuesta: (Nota: esta es sólo una de las posibles soluciones. Ignoramos los casos especiales como x≤0). ; Un código C que serviría de prueba ; #include <stdio.h> ; extern long funcion(long num,int x); ; long num=-3009;int x=2; ; main() { ; num=funcion(num,x); ; printf("%ld", num); // la respuesta aquí debe ser -3008. ; } .MODEL small .CODE PUBLIC _funcion _funcion proc near push bp mov bp,sp mov cx,word ptr [bp+8] ;x mov dx,word ptr [bp+6] ;parte alta de num mov ax,word ptr [bp+4] ;parte baja de num mov bl,0 ;bandera bl=0, positivo test dx,8000h ;no afecta al valor de dx jz positivo not dx ; si negativo, compl. a 2 de 32 bits not ax add ax,1 adc dx,0 mov bl,1 ;bandera bl=1, negativo positivo: shr dx,1 rcr ax,1 loop positivo ;desplaza a la derecha x veces mov cx,word ptr [bp+8] deshacer: shl ax,1 ;deshace los shifts anteriores rcl dx,1 ;si no, la magnitud del número es diferente loop deshacer cmp bl,1 ;si era negativo, vuelvo a dejarlo como estaba jne fin not dx not ax add ax,1 adc dx,0 fin: mov sp,bp pop bp ret _funcion endp end Otra posible solución sería crear una máscara con todos los bits a 1 salvo los x menos significativos y hacer la operación lógica and con num. Para la segunda parte del problema, las instrucciones ejecutadas de más por llamar a la función serían: En la función principal (main): 3 pushes de 16 bits para el paso de parámetros call al menos un add sp, 6 para deshacer los parámetros a lo que hay que añadir todas las líneas de la función ensamblador que no son estrictamente el "núcleo": push bp mov bp,sp mov cx,word ptr [bp+8] mov dx,word ptr [bp+6] mov ax,word ptr [bp+4] .............................. fin: mov sp,bp pop bp ret Como comentario final, este "costo" puede no ser despreciable en caso de recursos limitados (memoria, tiempo de ejecución, etc.). P2. (3 puntos) El siguiente código en ensamblador recorre un vector v, que comienza en la posición 0, calculando para cada v[i] el número de combinaciones que pueden darse con v[i] elementos tomados de dos en dos. El número de combinaciones de n elementos tomados de k en k es: Cnk = n ⋅ (n − 1) ⋅K⋅ (n − k + 1) k! ADDI R4,R0,#2 ADDI R1,R0,#40 LOOP: LW R2,0(R1) SUBI R3,R2,#1 MUL R2,R3,R2 DIV R2,R2,R4 SW 0(R1),R2 SUBI R1,R1,#4 BNEZ R1, LOOP Las instrucciones MUL y DIV tienen los operandos en registros de propósito general como ocurre en el WinDLX Se pide: a) Realizar la secuencia de ejecución del programa suponiendo un DLX con todos los desvíos de datos necesarios y con apuesta por salto no tomado. Indicar los bloqueos que se producen y que desvíos se activan en cada caso. Calcular el tiempo necesario para su ejecución suponiendo un reloj de 100Mhz. b) Realizar la secuencia de ejeución del programa suponiendo un DLX sin ningún tipo de desvío. Para optimizar la ejecución desenrollar el bucle 2 veces, reordenar y usar la técnica del salto retrasado. Calcular el tiempo necesario para su ejecución y la aceleración respecto a la máquina del apartado a suponiendo también un reloj de 100Mhz. c) Generalizar los resultados obtenidos en el apartado a para programas que calculen Cn3, Cn4,…, Cnk Nota: Explicar y justificar cualquier decisión tomada Solución: a) DLX con todos los desvíos de datos necesarios y con apuesta por salto no tomado ADDI R4,R0,#2 IF ADDI R1,R0,#40 LOOP: ID IF LW R2,0(R1) EX M WB ID EX M WB IF ID EX M WB IF ID - EX M IF - ID EX M WB IF ID EX M IF ID EX M WB IF ID EX M WB IF - ID EX M WB IF IF ID EX SUBI R3,R2,#1 MUL R2,R3,R2 DIV R2,R2,R4 SW 0(R1),R2 SUBI R1,R1,#4 WB BNEZ R1, LOOP LOOP: WB LW R2,0(R1) M Ta = (Ciclos_1 + 8*Ciclos_n + Ciclos_10) * Periodo de reloj = (12+8*10+13) * 10 ns = 1050 ns En la última iteración hay que incluir las 4 etapas que restan por ejecutarse. Al considerar salto no tomado, si hubiera instrucciones después del bucle, la última iteración tardaría un ciclo menos ya que no habría que repetir la etapa IF. b) Suponiendo que no hay ningún desvío de datos, desenrollando el bucle 2 veces y utilizando salto retrasado ADDI R4,R0,#2 ADDI R1,R0,#40 LOOP: LW R2,0(R1) SUBI R3,R2,#1 MUL R2,R3,R2 DIV R2,R2,R4 SW 0(R1),R2 LW R5,-4(R1) SUBI R6,R5,#1 MUL R5,R5,R4 DIV R5,R5,R4 SW -4(R1),R5 SUBI R1,R1,#8 BNEZ R1, LOOP LOOP: ADDI R1,R0,#40 ADDI R4,R0,#2 LW R2,0(R1) LW R5,-4(R1) SUBI R1,R1,#8 SUBI R3,R2,#1 SUBI R6,R5,#1 MUL R2,R3,R2 MUL R5,R6,R5 DIV R2,R2,R4 DIV R5,R5,R4 SW 8(R1),R2 DBNEZ R1, LOOP SW 4(R1),R5 LW R2,0(R1) IF ID IF EX ID IF ADDI R1,R0,#40 ADDI R4,R0,#2 LOOP: LW R2,0(R1) LW R5,-4(R1) SUBI R1,R1,#8 SUBI R3,R2,#1 SUBI R6,R5,#1 MUL R2,R3,R2 MUL R5,R6,R5 DIV R2,R2,R4 DIV R5,R5,R4 SW 8(R1),R2 DBNEZ R1, LOOP SW 4(R1),R5 M EX - WB M ID IF WB EX ID IF M EX ID IF WB M EX ID IF WB M EX ID IF WB M EX - WB M ID IF WB EX ID IF M EX - WB M ID IF Tb = (Ciclos_1 + 3*Ciclos_n + Ciclos_5) * Periodo de reloj = (18+3*15+19) * 10ns = 820 ns S = Ta/Tb = 1050/820 = 1,28 (mejora del 28%) El primer bloqueo sólo va a ocurrir en la primera iteración. WB EX ID IF M EX - WB M ID IF WB EX ID IF EX ID IF Una posible mejora (difícilmente obtenible por el compilador) sería la siguiente: Aprovechando que la multiplicación y la división tienen la misma prioridad el código podría reordenarse de la siguiente manera: ADDI R1,R0,#40 ADDI R4,R0,#2 LOOP: LW R2,0(R1) LW R5,-4(R1) SUBI R1,R1,#8 SUBI R3,R2,#1 SUBI R6,R5,#1 DIV R2,R2,R4 DIV R5,R5,R4 MUL R2,R3,R2 MUL R5,R6,R5 SW 8(R1),R2 BNEZ R1, LOOP SW 4(R1),R5 De esta manera conseguiríamos eliminar un bloqueo más en cada iteración. c) Generalizando los resultados del aparatado a para Cnk ADDI R4,R0,#k! ADDI R1,R0,#40 LOOP: LW R2,0(R1) SUB R3,R2,#1 MUL R2,R3,R2 SUBI R3,R3,#1 MUL R2,R3,R2 … (k-2 veces) SUBI R3,R3,#1 MUL R2,R3,R2 DIV R2,R2,R4 SW 0(R1),R2 SUBI R1,R1,#4 BNEZ R1, LOOP Tc = (Ciclos_1 + 8*Ciclos_n + Ciclos_10) * Periodo de reloj = [(12 + (k-2)*2) + 8*(10+(k-2)*2) + (13 + (k-2)*2)] * 10 ns = 200*k+650ns Las nuevas instrucciones no producen bloqueos.