Logo Studenta

UC3M _ Doble Grado Ingeniería Informática y ADE _ Arquitectura de Computadores _ Arquitectu

Esta es una vista previa del archivo. Inicie sesión para ver el archivo original

Arquitectura de Computadores/Ejercicios de Repaso/LEER.txtVer en clase. No los puedo compartir públicamente.
Arquitectura de Computadores/Examen Ordinario 2015-2016/ordinario-2016-sol.pdf
Arquitectura de Computadores/TEMA 1/Ejercicios Amdahl.pdf
Ejercicio 1 
Se dispone de una aplicación que realiza durante el 80% del tiempo cómputo y durante 
el 20% restante operaciones de E/S a disco. 
 Desarrollar una nueva versión de la aplicación que pueda ejecutar en un 
procesador de 8 núcleos. Se asume que el 90% de la parte de cómputo es 
paralelizable. 
 Sustituir el disco magnético por un disco SSD de mayor velocidad. 
 
a) Determine cuál debe ser la aceleración del nuevo disco con respecto al original 
para que compense la sustitución del disco en vez de la adquisición de 
procesador de 8 núcleos. Tenga en cuenta que el incremento de núcleos 
solamente afecta al cómputo. 
b) Asuma que el programa se puede paralelizar para cualquier número de 
procesadores y que la parte paralelizable es siempre el 90% de la parte de 
cómputo. Si la aceleración máxima de la parte de E/S a disco es 4. ¿Cuántos 
procesadores sería necesarios para alcanzar una aceleración global de 5? Tenga 
en cuenta que la aceleración global incluye cómputo y E/S. 
 
 
 
Ejercicio 2 
Se dispone de un computador con un solo núcleo que ejecuta una aplicación de 
evaluación de riesgos financieros. Esta aplicación es intensiva en cálculo, a lo que 
dedica el 90 % del tiempo. El 10 % restante lo dedica a esperar en operaciones de 
entrada/salida a disco. 
Del tiempo que la aplicación pasa ejecutando instrucciones de cálculo un 75 % 
del tiempo lo pasa ejecutando operaciones en coma flotante y un 25 % lo pasa 
ejecutando otras instrucciones. La ejecución de una instrucción de coma flotante 
requiere como promedio 12 CPI. El resto de instrucciones requieren como promedio 
4 CPI. 
Se está valorando la migración de esta aplicación a las siguientes alternativas, 
que no incorporan ninguna mejora para el tiempo de las operaciones de 
entrada/salida a disco: 
■ Alternativa A: Un procesador con un solo núcleo y con una frecuencia de reloj 
un 50 % más alta que la de la máquina original en el que las instrucciones de coma 
flotante requieren un 10 % más de ciclos por instrucción y el resto de 
instrucciones requieren un 25% más de ciclos por instrucción. 
■ Alternativa B: Un procesador con cuatro núcleos y con una frecuencia de reloj 
un 50% más baja que la de la máquina original, en el que las instrucciones de 
coma flotante requieren un 20 % menos de ciclos de reloj y el resto de 
instrucciones los mismos ciclos de reloj. 
Se pide responder de forma justificada a las siguientes cuestiones: 
1. ¿Cuál será la aceleración/deceleración global de la aplicación en el caso A? 
2. ¿Cuál será la aceleración/deceleración global de la aplicación en el caso B si se 
asume que la parte de cálculo es totalmente paralelizable mientras la 
entrada/salida no admite ningún tipo de paralelización? 
 
Arquitectura de Computadores/TEMA 2/es-m6-01-openmp-lect.pdf
Programación paralela con OpenMP
Programación paralela con OpenMP
Arquitectura de Computadores
J. Daniel García Sánchez (coordinador)
David Expósito Singh
Javier García Blas
J. Manuel Pérez Lobato
Grupo ARCOS
Departamento de Informática
Universidad Carlos III de Madrid
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 1/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 2/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
¿Qué es OpenMP?
Es un API (y un conjunto de directivas) para expresar
aplicaciones paralelas en sistemas de memoria
compartida.
Componentes:
Directivas de compilador.
Funciones de biblioteca.
Variables de entorno.
Simplifica la forma de escribir programas paralelos.
Mappings para FORTRAN, C y C++.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 3/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Construcciones
Directivas:
#pragma omp directiva [clausulas]
Ejemplo: Fijar el número de hilos.
#pragma omp parallel num_threads(4)
Funciones de biblioteca
#include <omp.h> // Incluir para llamar funciones OpenMP
ejemplo: Obtener el número de hilos usado.
int n = omp_get_num_threads();
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 4/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Construcciones
Directivas:
#pragma omp directiva [clausulas]
Ejemplo: Fijar el número de hilos.
#pragma omp parallel num_threads(4)
Funciones de biblioteca
#include <omp.h> // Incluir para llamar funciones OpenMP
ejemplo: Obtener el número de hilos usado.
int n = omp_get_num_threads();
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 4/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Ejercicio 1: Secuencial
exseq.cpp
#include <iostream>
int main() {
using namespace std;
int id = 0;
cout << "Hola(" << id << ") " ;
cout << "Mundo(" << id << ")";
return 0;
}
Imprime en salida estándar.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 5/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Ejercicio 1: Paralelo
exseq.cpp
#include <iostream>
#include <omp.h>
int main() {
using namespace std;
#pragma omp parallel
{
int id = omp_get_thread_num();
cout << "Hola(" << id << ") " ;
cout << "Mundo(" << id << ")";
}
return 0;
}
Flags de compilación:
gcc: -fopenmp
Intel Linux: -openmp
Intel Windows:
/Qopenmp
Microsft Visual Studio:
/openmp
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 6/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Ejercicio 1
Objetivo: Verificar que el entorno funciona.
Actividades:
1 Compilar la versión secuencial y ejecutar.
2 Compilar la versión paralela y ejecutar.
3 Introduzca la función omp_get_num_threads() para
imprimir el número de hilos:
a) Antes del pragma.
b) Justo después del pragma.
c) Dentro del bloque.
d) Antes de salir del programa, pero fuera del bloque.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 7/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Ejercicio 1
Objetivo: Verificar que el entorno funciona.
Actividades:
1 Compilar la versión secuencial y ejecutar.
2 Compilar la versión paralela y ejecutar.
3 Introduzca la función omp_get_num_threads() para
imprimir el número de hilos:
a) Antes del pragma.
b) Justo después del pragma.
c) Dentro del bloque.
d) Antes de salir del programa, pero fuera del bloque.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 7/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Observaciones
Modelo de memoria compartida multi-hilo.
Comunicación mediante variables compartidas.
Compartición accidental→ condiciones de carrera.
Resultado dependiente de la planificación de los hilos.
Evitar condiciones de carrera.
Sincronización para evitar conflictos.
Coste de sincronización.
Modificación en patrón de accesos.
Minimizar sincronizaciones necesarias.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 8/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Observaciones
Modelo de memoria compartida multi-hilo.
Comunicación mediante variables compartidas.
Compartición accidental→ condiciones de carrera.
Resultado dependiente de la planificación de los hilos.
Evitar condiciones de carrera.
Sincronización para evitar conflictos.
Coste de sincronización.
Modificación en patrón de accesos.
Minimizar sincronizaciones necesarias.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 8/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Introducción
Observaciones
Modelo de memoria compartida multi-hilo.
Comunicación mediante variables compartidas.
Compartición accidental→ condiciones de carrera.
Resultado dependiente de la planificación de los hilos.
Evitar condiciones de carrera.
Sincronización para evitar conflictos.
Coste de sincronización.
Modificación en patrón de accesos.
Minimizar sincronizaciones necesarias.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 8/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 9/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Paralelismo fork-join
Aplicación secuencial con secciones paralelas:
Hilo maestro: Iniciado con el programa principal.
En una sección paralela se arranca un conjunto de hilos.
Se puede anidar el paralelismo.
Una región paralela es un bloque marcado con la directiva
parallel.
#pragama omp parallel
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 10/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Paralelismo fork-join
Aplicación secuencial con secciones paralelas:
Hilo maestro: Iniciado con el programa principal.
En una sección paralela se arranca un conjunto de hilos.
Se puede anidar el paralelismo.
Una región paralela es un bloque marcado con la directiva
parallel.
#pragama omp parallel
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 10/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Selección del número de hilos
Invocando a una función
de biblioteca.
Ejemplo
// ...
omp_set_num_threads(4);
#pragma omp parallel
{
// Región paralela
}
Directiva OpenMP.
Ejemplo
// ...
#pragma omp parallel num_threads(4)
{
// Región paralela
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 11/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Selección del número de hilos
Invocando a una función
de biblioteca.
Ejemplo
// ...
omp_set_num_threads(4);
#pragma omp parallel
{
// Región paralela
}
Directiva OpenMP.
Ejemplo
// ...
#pragma omp parallel num_threads(4)
{
// Región paralela
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 11/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Ejercicio 2: Cálculo de π
Cálculo de π.
π =
∫ 1
0
4
1 + x2
dx
Aproximación:
π ≈
N∑
i=0
F (xi)∆x
Suma del área de N rectángulos.
Base: ∆x .
Altura: F (xi ).
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 12/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Ejercicio 2: Cálculo de π
Cálculo de π.
π =
∫ 1
0
4
1 + x2
dx
Aproximación:
π ≈
N∑
i=0
F (xi)∆x
Suma del área de N rectángulos.
Base: ∆x .
Altura: F (xi ).
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 12/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Ejercicio 2: Versión secuencial
Cálculo de π
#include <iostream>
#include <iomanip>
#include <chrono>
int main() {
using namespace std;
using namespace std::chrono;
constexpr long nsteps = 10000000;
double step = 1.0 / double(nsteps);
using clk = high_resolution_clock;
auto t1 = clk :: now();
double sum = 0.0;
for ( int i=0;i<nsteps; ++i) {
double x = (i+0.5) ∗ step;
sum += 4.0 / (1.0 + x ∗ x) ;
}
double pi = step ∗ sum;
auto t2 = clk :: now();
auto diff = duration_cast<microseconds>(t2−t1);
cout << "PI= " << setprecision(10) << pi << endl;
cout << "Tiempo= " << diff .count() << "us" << endl;
return 0;
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 13/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Medición del tiempo en C++11
Ficheros de include:
#include <chrono>
Tipo para el reloj:
using clk = chrono::high_resolution_clock;
Obtener un punto del tiempo:
auto t1 = clk :: now();
Diferencias de tiempo (puede especificar unidad).
auto diff = duration_cast<microseconds>(t2−t1);
Obtención del valor de la diferencia.
cout << diff .count() ;
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 14/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Ejemplo de medida de tiempo
Ejemplo
#include <chrono>
void f () {
using namespace std;
using namespace std::chrono;
using clk = chrono::high_resolution_clock;
auto t1 = clk :: now();
g() ;
auto t2 = clk :: now();
auto diff = duration_cast<microseconds>(t2−t1);
cout << "Time= " << diff .count << "microseconds" << endl;
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 15/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Medición de tiempo en OpenMP
Punto del tiempo.
double t1 = omp_get_wtime();
Diferencia de tiempo.
double t1 = omp_get_wtime();
double t2 = omp_get_wtime();
double diff = t2−t1;
Diferencia de tiempo entre 2 ticks sucesivos:
double tick = omp_get_wtick();
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 16/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Hilos en OpenMP
Ejercicio 2
Crear una versión paralela del programa de cálculo de π
usando una clausula parallel.
Observaciones:
Incluya mediciones de tiempo.
Imprima el número de hilos que se están usando.
Tenga cuidado con las variables compartidas.
Idea: Use un array y acumule una suma parcial en cada
hilo en la región paralela.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 17/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 18/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
Mecanismos de sincronización
Sincronización: Mecanismo usado para establecer
restricciones sobre el orden de acceso a datos
compartidos.
Objetivo: Evitar carreras de datos.
Alternativas:
Alto nivel: critical, atomic, barrier, ordered.
Bajo nivel: flush, cerrojos.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 19/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
Mecanismos de sincronización
Sincronización: Mecanismo usado para establecer
restricciones sobre el orden de acceso a datos
compartidos.
Objetivo: Evitar carreras de datos.
Alternativas:
Alto nivel: critical, atomic, barrier, ordered.
Bajo nivel: flush, cerrojos.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 19/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
critical
Garantiza exclusión mutua.
Solamente un hilo a la vez puede entrar en la región
crítica.
Ejemplo
#pragma omp parallel
{
for ( int i=0;i<max;++i) {
x = f ( i ) ;
#pragma omp critical
g(x) ;
}
Las llamadas a f() se realiza en
paralelo.
Solamente un hilo puede entrar a la
vez en g().
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 20/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
critical
Garantiza exclusión mutua.
Solamente un hilo a la vez puede entrar en la región
crítica.
Ejemplo
#pragma omp parallel
{
for ( int i=0;i<max;++i) {
x = f ( i ) ;
#pragma omp critical
g(x) ;
}
Las llamadas a f() se realiza en
paralelo.
Solamente un hilo puede entrar a la
vez en g().
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 20/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
atomic
Garantiza la actualización atómica de una posición de
memoria.
Evita carrera de datos en actualización a variable
Ejemplo
#pragma omp parallel
{
for ( int i=0;i<max;++i) {
x = f ( i ) ;
#pragma omp atomic
s += g(x)
}
Las llamadas a f() se realiza en
paralelo.
Las actualizaciones a s son
thread-safe.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 21/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
atomic
Garantiza la actualización atómica de una posición de
memoria.
Evita carrera de datos en actualización a variable
Ejemplo
#pragma omp parallel
{
for ( int i=0;i<max;++i) {
x = f ( i ) ;
#pragma omp atomic
s += g(x)
}
Las llamadas a f() se realiza en
paralelo.
Las actualizaciones a s son
thread-safe.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 21/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización
Ejercicio 3
Modifique su programa del ejercicio 2.
Evalúe:
a) Sección crítica.
b) Acceso atómico.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 22/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 23/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Parallel for
División de bucle: Realiza una partición de las
iteraciones de un bucle entre los hilos disponible.
Sintaxis
#pragma omp parallel
{
#pragma omp for
for ( i=0; i<n; ++i) {
f ( i ) ;
}
}
omp for→ División de bucle for.
Se generar una copia privada de i
para cada hilo.
Se puede hacer también con
private(i)
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 24/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Parallel for
División de bucle: Realiza una partición de las
iteraciones de un bucle entre los hilos disponible.
Sintaxis
#pragma omp parallel
{
#pragma omp for
for ( i=0; i<n; ++i) {
f ( i ) ;
}
}
omp for→ División de bucle for.
Se generar una copia privada de i
para cada hilo.
Se puede hacer también con
private(i)
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 24/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Ejemplo
Código secuencial
for ( i=0;i<max;++i) { u[ i ] = v[ i ] + w[i ]; }
Región paralela
#pragma omp parallel
{
int id = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int istart = id ∗ max / nthreads;
int iend = ( id==nthreads−1) ?
(( id + 1) ∗ max / nthreads):max;
for ( int i= istart ; i<iend;++i)
{ u[ i ] = v[ i ] + w[i ]; }
}
Región paralela + Bucle
paralelo
#pragma omp parallel
#pragma omp for
for ( i=0;i<max;++i)
{ u[ i ] = v[ i ] + w[i ]; }
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 25/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Ejemplo
Código secuencial
for ( i=0;i<max;++i) { u[ i ] = v[ i ] + w[i ]; }
Región paralela
#pragma omp parallel
{
int id = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int istart = id ∗ max / nthreads;
int iend = ( id==nthreads−1) ?
(( id + 1) ∗ max / nthreads):max;
for ( int i= istart ; i<iend;++i)
{ u[ i ] = v[ i ] + w[i ]; }
}
Región paralela + Bucle
paralelo
#pragma omp parallel
#pragma omp for
for ( i=0;i<max;++i)
{ u[ i ] = v[ i ] + w[i ]; }
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 25/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Ejemplo
Código secuencial
for ( i=0;i<max;++i) { u[ i ] = v[ i ] + w[i ]; }
Región paralela
#pragma omp parallel
{
int id = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int istart = id ∗ max / nthreads;
int iend = ( id==nthreads−1) ?
(( id + 1) ∗ max / nthreads):max;
for ( int i= istart ; i<iend;++i)
{ u[ i ] = v[ i ] + w[i ]; }
}
Región paralela + Bucle
paralelo
#pragma omp parallel
#pragma omp for
for ( i=0;i<max;++i)
{ u[ i ] = v[ i ] + w[i ]; }
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 25/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Construcción combinada
Se puede usar una forma abreviada combinando las dos
directivas.
Dos directivas
vector<double> vec(max);
#pragma omp parallel
{
#pragma omp for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
}
Directiva combinada
vector<double> vec(max);
#pragma omp parallel for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 26/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Construcción combinada
Se puede usar una forma abreviada combinando las dos
directivas.
Dos directivas
vector<double> vec(max);
#pragma omp parallel
{
#pragma omp for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
}
Directiva combinada
vector<double> vec(max);
#pragma omp parallel for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 26/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Construcción combinada
Se puede usar una forma abreviada combinando las dos
directivas.
Dos directivas
vector<double> vec(max);
#pragma omp parallel
{
#pragma omp for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
}
Directiva combinada
vector<double> vec(max);
#pragma omp parallel for
for ( i=0; i<max; ++i) {
vec[ i ] = generate(i) ;
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 26/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Reducciones
Ejemplo
double sum = 0.0;
vector<double> v(max);
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Una reducción es una operación de
acumulación en un bucle.
Clausula de reducción: reduction
(op:var)
Efectos:
Copia privada de
cada variable.
Actualización de
copia local en cada
iteración.
Copias locales
combinadas al final.
Ejemplo
double sum = 0.0;
vector<double> v(max);
#pragma omp parallel for reduction(+:suma)
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 27/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Reducciones
Ejemplo
double sum = 0.0;
vector<double> v(max);
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Una reducción es una operación de
acumulación en un bucle.
Clausula de reducción: reduction
(op:var)
Efectos:
Copia privada de
cada variable.
Actualización de
copia local en cada
iteración.
Copias locales
combinadas al final.
Ejemplo
double sum = 0.0;
vector<double> v(max);
#pragma omp parallel for reduction(+:suma)
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 27/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Reducciones
Ejemplo
double sum = 0.0;
vector<double> v(max);
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Una reducción es una operación de
acumulación en un bucle.
Clausula de reducción: reduction
(op:var)
Efectos:
Copia privada de
cada variable.
Actualización de
copia local en cada
iteración.
Copias locales
combinadas al final.
Ejemplo
double sum = 0.0;
vector<double> v(max);
#pragma omp parallel for reduction(+:suma)
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Arquitectura de
Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 27/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Reducciones
Ejemplo
double sum = 0.0;
vector<double> v(max);
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Una reducción es una operación de
acumulación en un bucle.
Clausula de reducción: reduction
(op:var)
Efectos:
Copia privada de
cada variable.
Actualización de
copia local en cada
iteración.
Copias locales
combinadas al final.
Ejemplo
double sum = 0.0;
vector<double> v(max);
#pragma omp parallel for reduction(+:suma)
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 27/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Reducciones
Ejemplo
double sum = 0.0;
vector<double> v(max);
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Una reducción es una operación de
acumulación en un bucle.
Clausula de reducción: reduction
(op:var)
Efectos:
Copia privada de
cada variable.
Actualización de
copia local en cada
iteración.
Copias locales
combinadas al final.
Ejemplo
double sum = 0.0;
vector<double> v(max);
#pragma omp parallel for reduction(+:suma)
for ( int i=0; i<max; ++i) {
suma += v[i];
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 27/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Operaciones de reducción
Operaciones que son asociativas.
(a⊕ b)⊕ c = a⊕ (b ⊕ c)
Valor inicial definido por la operación.
Operadores básicos:
+ (valor inicial: 0).
* (valor inicial: 1).
- (valor inicial: 0).
Operadores avanzados:
& (valor inicial: 0).
| (valor inicial: 0).
ˆ (valor inicial: 0).
&& (valor inicial: 1).
|| (valor inicial: 0).
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 28/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Operaciones de reducción
Operaciones que son asociativas.
(a⊕ b)⊕ c = a⊕ (b ⊕ c)
Valor inicial definido por la operación.
Operadores básicos:
+ (valor inicial: 0).
* (valor inicial: 1).
- (valor inicial: 0).
Operadores avanzados:
& (valor inicial: 0).
| (valor inicial: 0).
ˆ (valor inicial: 0).
&& (valor inicial: 1).
|| (valor inicial: 0).
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 28/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Operaciones de reducción
Operaciones que son asociativas.
(a⊕ b)⊕ c = a⊕ (b ⊕ c)
Valor inicial definido por la operación.
Operadores básicos:
+ (valor inicial: 0).
* (valor inicial: 1).
- (valor inicial: 0).
Operadores avanzados:
& (valor inicial: 0).
| (valor inicial: 0).
ˆ (valor inicial: 0).
&& (valor inicial: 1).
|| (valor inicial: 0).
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 28/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Bucles paralelos
Ejercicio 4
Modifique el programa de cálculo de π.
Intente que el programa sea lo más parecido posible al
programa secuencial.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 29/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 30/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Barreras
Permite sincronizar todos los hilos en un punto.
Se espera hasta que todos los puntos llegan a la barrera.
Ejemplo
#pragma omp parallel
{
int id = omp_get_thread_num();
v[ id ] = f ( id ) ;
#pragma omp barrier
#pragma omp for
for ( int i=0;i<max;++i) {
w[i ] = g( i ) ;
} // Barrera implí cita
#pragma omp for nowait
for ( int i=0;i<max;++i) {
w[i ] = g( i ) ;
} // nowait −> No hay barrera implícita
v[ i ] = h( i ) ;
} // Barrera implí cita
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 31/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Ejecución única: master
La clausula master marca un bloque que solamente se
ejecuta en el hilo maestro.
Ejemplo
#pragma omp parallel
{
f () ; // En todos los hilos
#pragma omp master
{
g() ; // Solamente en maestro
h() ; // Solamente en maestro
}
i () ; // En todos los hilos
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 32/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Ejecución única: single
La clausula single marca un bloque que solamente se
ejecuta en un hilo.
No tiene por qué ser el hilo maestro.
Ejemplo
#pragma omp parallel
{
f () ; // En todos los hilos
#pragma omp single
{
g() ; // Solamente en algún hilo
h() ; // Solamente en algún hilo
}
i () ; // En todos los hilos
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 33/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Ordenación
Una región ordered se ejecuta en orden secuencial.
Ejemplo
#pragma omp parallel
{
#pragma omp for ordered reduction(+:res)
for ( int i=0;i<max;++i) {
double tmp = f(i) ;
#pragma ordered
res += g(tmp);
}
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 34/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Cerrojos simples
Cerrojos de la biblioteca OpenMP.
También hay cerrojos anidados.
Ejemplo
omp_lock_t l;
omo_init_lock(&l);
#pragma omp parallel
{
int id = omp_get_thread_num();
double x = f( i ) ;
omp_set_lock(&l);
cout << "ID=" << id << " tmp= " << tmp << endl;
omp_unset_lock(&l);
}
omp_destroy_lock(&l);
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 35/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Otras funciones de biblioteca
Cerrojos anidados:
omp_init_nest_lock(), omp_set_nest_lock(),
omp_unset_nest_lock(), omp_test_next_lock(),
omp_destroy_nest_lock().
Consulta de procesadores:
omp_num_procs().
Número de hilos:
omp_set_num_threads(), omp_get_num_threads(),
omp_get_thread_num(), omp_get_max_threads().
Comprobación de región paralela:
omp_in_parallel().
Selección dinámica de número de hilos:
omp_set_dynamic(), omp_get_dynamic().
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 36/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Sincronización con master
Variables de entorno
Número de hilos por defecto:
OMP_NUM_THREADS
Modo de planificación:
OMP_SCHEDULE
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 37/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 38/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
Atributos de almacenamiento
Modelo de programación en memoria compartida:
Variables compartidas.
Variables privadas.
Compartidas:
Variables globales (alcance de fichero y espacio de
nombres).
Variables static.
Objetos en memoria dinámica (malloc() y new).
Privadas:
Variables locales de funciones invocadas desde una región
paralela.
Variables locales definidas dentro de un bloque.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 39/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
Atributos de almacenamiento
Modelo de programación en memoria compartida:
Variables compartidas.
Variables privadas.
Compartidas:
Variables globales (alcance de fichero y
espacio de
nombres).
Variables static.
Objetos en memoria dinámica (malloc() y new).
Privadas:
Variables locales de funciones invocadas desde una región
paralela.
Variables locales definidas dentro de un bloque.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 39/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
Atributos de almacenamiento
Modelo de programación en memoria compartida:
Variables compartidas.
Variables privadas.
Compartidas:
Variables globales (alcance de fichero y espacio de
nombres).
Variables static.
Objetos en memoria dinámica (malloc() y new).
Privadas:
Variables locales de funciones invocadas desde una región
paralela.
Variables locales definidas dentro de un bloque.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 39/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
Modificación de atributos de almacenamiento
Atributos en clausulas paralelas:
shared.
private.
firstprivate.
private crea una nueva copia local por hilo.
El valor de las copias no se inicializa.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for private(x)
for ( int i=0;i<max;++i) {
x += i ; // x inicialmente vale 17
}
cout << x << endl; // x==17
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 40/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
Modificación de atributos de almacenamiento
Atributos en clausulas paralelas:
shared.
private.
firstprivate.
private crea una nueva copia local por hilo.
El valor de las copias no se inicializa.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for private(x)
for ( int i=0;i<max;++i) {
x += i ; // x inicialmente vale 17
}
cout << x << endl; // x==17
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 40/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
firstprivate
Caso particular de private.
Cada copia privada se inicia con el valor de la variable en
el hilo maestro.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for firstprivate (x)
for (long i=0;i<maxval;++i) {
x += i ; // x inicialmente vale 17
}
std :: cout << x << std ::endl; // x==17
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 41/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
firstprivate
Caso particular de private.
Cada copia privada se inicia con el valor de la variable en
el hilo maestro.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for firstprivate (x)
for (long i=0;i<maxval;++i) {
x += i ; // x inicialmente vale 17
}
std :: cout << x << std ::endl; // x==17
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 41/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
lastprivate
Pasa el valor de una variable privada de la última iteración
secuencial a la variable global.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for firstprivate (x) lastprivate (x)
for (long i=0;i<maxval;++i) {
x += i ; // x inicialmente vale 17
}
std :: cout << x << std ::endl; // x valor iteraci ón i==maxval−1
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 42/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Compartición de datos
lastprivate
Pasa el valor de una variable privada de la última iteración
secuencial a la variable global.
Ejemplo
void f () {
int x = 17;
#pragma omp parallel for firstprivate (x) lastprivate (x)
for (long i=0;i<maxval;++i) {
x += i ; // x inicialmente vale 17
}
std :: cout << x << std ::endl; // x valor iteraci ón i==maxval−1
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 42/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 43/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Secciones
Define un conjunto de secciones
de código.
Cada sección se pasa a un hilo
distinto.
Por defecto hay una barrera al
final del bloque sections
Ejemplo
#pragma omp parallel
{
#pragma omp sections
{
#pragma omp section
f () ;
#pragma omp section
g() ;
#pragma omp section
h() ;
}
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 44/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Secciones
Define un conjunto de secciones
de código.
Cada sección se pasa a un hilo
distinto.
Por defecto hay una barrera al
final del bloque sections
Ejemplo
#pragma omp parallel
{
#pragma omp sections
{
#pragma omp section
f () ;
#pragma omp section
g() ;
#pragma omp section
h() ;
}
}
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 44/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Planificación de bucles
schedule(static) | schedule(static,n):
Planifica bloques de iteraciones (de tamaño n) para cada
hilo.
schedule(dynamic) | schedule(dynamic,n):
Cada hilo toma un bloque de n iteraciones de una cola
hasta que se han procesado todas.
schedule(guided) | schedule(guided,n):
Cada hilo toma un bloque iteraciones hasta que se han
procesado todas. Se comienza con un tamaño de bloque
grande y se va reduciendo hasta llegar a un tamaño n.
schedule(runtime) | schedule(runtime,n):
Se usa lo indicado en OMP_SCHEDULE o por la biblioteca
en tiempo de ejecución.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 45/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Planificación de bucles
schedule(static) | schedule(static,n):
Planifica bloques de iteraciones (de tamaño n) para cada
hilo.
schedule(dynamic) | schedule(dynamic,n):
Cada hilo toma un bloque de n iteraciones de una cola
hasta que se han procesado todas.
schedule(guided) | schedule(guided,n):
Cada hilo toma un bloque iteraciones hasta que se han
procesado todas. Se comienza con un tamaño de bloque
grande y se va reduciendo hasta llegar a un tamaño n.
schedule(runtime) | schedule(runtime,n):
Se usa lo indicado en OMP_SCHEDULE o por la biblioteca
en tiempo de ejecución.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 45/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Planificación de bucles
schedule(static) | schedule(static,n):
Planifica bloques de iteraciones (de tamaño n) para cada
hilo.
schedule(dynamic) | schedule(dynamic,n):
Cada hilo toma un bloque de n iteraciones de una cola
hasta que se han procesado todas.
schedule(guided) | schedule(guided,n):
Cada hilo toma un bloque iteraciones hasta que se han
procesado todas. Se comienza con un tamaño de bloque
grande y se va reduciendo hasta llegar a un tamaño n.
schedule(runtime) | schedule(runtime,n):
Se usa lo indicado en OMP_SCHEDULE o por la biblioteca
en tiempo de ejecución.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 45/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Secciones y planificación
Planificación de bucles
schedule(static) | schedule(static,n):
Planifica bloques de iteraciones (de tamaño n) para cada
hilo.
schedule(dynamic) | schedule(dynamic,n):
Cada hilo toma un bloque de n iteraciones de una cola
hasta que se han procesado todas.
schedule(guided) | schedule(guided,n):
Cada hilo toma un bloque iteraciones hasta que se han
procesado todas. Se comienza con un tamaño de bloque
grande y se va reduciendo hasta llegar a un tamaño n.
schedule(runtime) | schedule(runtime,n):
Se usa lo indicado en OMP_SCHEDULE
o por la biblioteca
en tiempo de ejecución.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 45/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
1 Introducción
2 Hilos en OpenMP
3 Sincronización
4 Bucles paralelos
5 Sincronización con master
6 Compartición de datos
7 Secciones y planificación
8 Conclusión
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 46/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Resumen
OpenMP permite anotar código secuencial para hacer uso
de paralelismo fork-join.
Basado en el concepto de región paralela.
Los mecanismos de sincronización pueden ser de alto
nivel o bajo nivel.
Los bucles paralelos combinados con las reducciones
permiten preservar el código original de muchos
algoritmos.
Los atributos de almacenamiento permiten controlar las
copias y compartición de datos con las regiones paralelas.
OpenMP ofrece varios tipos de planificación.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 47/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Resumen
OpenMP permite anotar código secuencial para hacer uso
de paralelismo fork-join.
Basado en el concepto de región paralela.
Los mecanismos de sincronización pueden ser de alto
nivel o bajo nivel.
Los bucles paralelos combinados con las reducciones
permiten preservar el código original de muchos
algoritmos.
Los atributos de almacenamiento permiten controlar las
copias y compartición de datos con las regiones paralelas.
OpenMP ofrece varios tipos de planificación.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 47/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Resumen
OpenMP permite anotar código secuencial para hacer uso
de paralelismo fork-join.
Basado en el concepto de región paralela.
Los mecanismos de sincronización pueden ser de alto
nivel o bajo nivel.
Los bucles paralelos combinados con las reducciones
permiten preservar el código original de muchos
algoritmos.
Los atributos de almacenamiento permiten controlar las
copias y compartición de datos con las regiones paralelas.
OpenMP ofrece varios tipos de planificación.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 47/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Resumen
OpenMP permite anotar código secuencial para hacer uso
de paralelismo fork-join.
Basado en el concepto de región paralela.
Los mecanismos de sincronización pueden ser de alto
nivel o bajo nivel.
Los bucles paralelos combinados con las reducciones
permiten preservar el código original de muchos
algoritmos.
Los atributos de almacenamiento permiten controlar las
copias y compartición de datos con las regiones paralelas.
OpenMP ofrece varios tipos de planificación.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 47/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Resumen
OpenMP permite anotar código secuencial para hacer uso
de paralelismo fork-join.
Basado en el concepto de región paralela.
Los mecanismos de sincronización pueden ser de alto
nivel o bajo nivel.
Los bucles paralelos combinados con las reducciones
permiten preservar el código original de muchos
algoritmos.
Los atributos de almacenamiento permiten controlar las
copias y compartición de datos con las regiones paralelas.
OpenMP ofrece varios tipos de planificación.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 47/49
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Referencias
Libros:
An Introduction to Parallel Programming. P. Pacheco.
Morgan Kaufmann, 2011. (Cáp 5).
Multicore and GPU Programming. G. Barlas. Morgan
Kaufmann. 2014. (Cáp 4).
Páginas Web:
OpenMP: http://www.openmp.org.
Lawrence Livermore National Laboratory Tutorial: https:
//computing.llnl.gov/tutorials/openMP/.
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 48/49
http://www.openmp.org
https://computing.llnl.gov/tutorials/openMP/
https://computing.llnl.gov/tutorials/openMP/
http://www.arcos.inf.uc3m.es
Programación paralela con OpenMP
Conclusión
Programación paralela con OpenMP
Arquitectura de Computadores
J. Daniel García Sánchez (coordinador)
David Expósito Singh
Javier García Blas
J. Manuel Pérez Lobato
Grupo ARCOS
Departamento de Informática
Universidad Carlos III de Madrid
Arquitectura de Computadores – Grupo ARCOS – http://www.arcos.inf.uc3m.es 49/49
http://www.arcos.inf.uc3m.es
	Introducción
	Hilos en OpenMP
	Sincronización
	Bucles paralelos
	Sincronización con master
	Compartición de datos
	Secciones y planificación
	Conclusión
Arquitectura de Computadores/TEMA 2/OpenMP_consoluciones.zip
Lab1/ej1/ex1par.cpp
#include <iostream>
#include <omp.h>
int main() {
 using namespace std;
 #pragma omp parallel
 {
 int id = omp_get_thread_num();
 cout << "Hola(" << id << ") ";
 cout << "Mundo(" << id << ")";
 }
 return 0;
}
Lab1/ej1/ex1seq.cpp
#include <iostream>
int main() {
 using namespace std;
 int id = 0;
 cout << "Hola(" << id << ") ";
 cout << "Mundo(" << id << ")";
 return 0; 
}
Lab1/ej1/Makefile
CC=g++
CFLAGS=-std=c++14
PARFLAGS=-fopenmp
all: bin bin/seq bin/par
bin:
	mkdir -p bin
bin/seq:	ex1seq.cpp
	$(CC) $(CFLAGS) $< -o $@
bin/par:	ex1par.cpp
	$(CC) $(CFLAGS) $(PARFLAGS) $< -o $@
Lab1/ej2/Makefile
CC=g++
CFLAGS=-std=c++14 -O3 -DNDEBUG
PARFLAGS=-fopenmp
all: bin bin/seq bin/par 
bin:
	mkdir -p bin
bin/seq:	seq.cpp
	$(CC) $(CFLAGS) $< -o $@
bin/par:	par.cpp
	$(CC) $(CFLAGS) $(PARFLAGS) $< -o $@
Lab1/ej2/par.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
#include <vector>
#include <algorithm>
#include <omp.h>
#include <iostream>
int main() {
 using namespace std;
 using namespace std::chrono;
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 int nthreads;
 #pragma omp parallel
 nthreads = omp_get_num_threads();
 vector<double> sum(nthreads);
 using clk = high_resolution_clock;
 auto t1 = clk::now();
 #pragma omp parallel 
 {
 int id = omp_get_thread_num();
 for (int i=id; i<nsteps; i+=nthreads) 
 {
 double x = (i+0.5) * step;
 sum[id] += 4.0 / (1.0 + x * x);
 }
 }
 double pi = step * accumulate(begin(sum), end(sum), 0);
 auto t2 = clk::now();
 auto diff = duration_cast<microseconds>(t2-t1);
 cout << "Threads= " << nthreads << endl;
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Tiempo= " << diff.count() << "us" << endl;
 return 0; 
}
Lab1/ej2/seq.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
int main() {
 using namespace std;
 using namespace std::chrono;
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 using clk = high_resolution_clock;
 auto t1 = clk::now();
 double sum = 0.0;
 for (int i=0;i<nsteps; ++i) {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 double pi = step * sum;
 auto t2 = clk::now();
 auto diff = duration_cast<microseconds>(t2-t1);
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Tiempo= " << diff.count() << "us" << endl;
 return 0; 
}
Lab1/ej3/Makefile
CC=g++
CFLAGS=-std=c++14 -O3 -DNDEBUG
PARFLAGS=-fopenmp
all: bin bin/seq bin/parcrit bin/paratom
bin:
	mkdir -p bin
bin/seq:	seq.cpp
	$(CC) $(CFLAGS) $< -o $@
bin/parcrit:	parcrit.cpp
	$(CC) $(CFLAGS) $(PARFLAGS) $< -o $@
bin/paratom:	paratom.cpp
	$(CC) $(CFLAGS) $(PARFLAGS) $< -o $@
Lab1/ej3/paratom.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
#include <vector>
#include <algorithm>
#include <omp.h>
#include <iostream>
int main() {
 using namespace std;
 using namespace std::chrono;
constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 int nthreads;
 #pragma omp parallel
 nthreads = omp_get_num_threads();
 double pi = 0.0;
 using clk = high_resolution_clock;
 auto t1 = clk::now();
 #pragma omp parallel 
 {
 int id = omp_get_thread_num();
 double sum = 0.0;
 for (int i=id; i<nsteps; i+=nthreads)
 {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 #pragma omp atomic
 pi += sum * step;
 }
 auto t2 = clk::now();
 auto diff = duration_cast<microseconds>(t2-t1);
 cout << "Threads= " << nthreads << endl;
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Tiempo= " << diff.count() << "us" << endl;
 return 0; 
}
Lab1/ej3/parcrit.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
#include <vector>
#include <algorithm>
#include <omp.h>
#include <iostream>
int main() {
 using namespace std;
 using namespace std::chrono;
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 int nthreads;
 #pragma omp parallel
 nthreads = omp_get_num_threads();
 double pi = 0.0;
 using clk = high_resolution_clock;
 auto t1 = clk::now();
 #pragma omp parallel 
 {
 int id = omp_get_thread_num();
 double sum = 0.0;
 for (int i=id; i<nsteps; i+=nthreads)
 {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 #pragma omp critical
 pi += sum * step;
 }
 auto t2 = clk::now();
 auto diff = duration_cast<microseconds>(t2-t1);
 cout << "Threads= " << nthreads << endl;
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Tiempo= " << diff.count() << "us" << endl;
 return 0; 
}
Lab1/ej3/seq.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
int main() {
 using namespace std;
 using namespace std::chrono;
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 using clk = high_resolution_clock;
 auto t1 = clk::now();
 double sum = 0.0;
 for (int i=0;i<nsteps; ++i) {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 double pi = step * sum;
 auto t2 = clk::now();
 auto diff = duration_cast<microseconds>(t2-t1);
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Tiempo= " << diff.count() << "us" << endl;
 return 0; 
}
Lab1/ej4/Makefile
CC=g++
CFLAGS=-std=c++14 -O3 -DNDEBUG
PARFLAGS=-fopenmp
all: bin bin/seq bin/par 
bin:
	mkdir -p bin
bin/seq:	seq.cpp
	$(CC) $(CFLAGS) $< -o $@
bin/par:	par.cpp
	$(CC) $(CFLAGS) $(PARFLAGS) $< -o $@
Lab1/ej4/par.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
#include <omp.h>
int main() {
 using namespace std;
 using namespace std::chrono;
 using clk = chrono::high_resolution_clock;
 
 auto t1 = clk::now();
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 double sum = 0.0;
 #pragma omp parallel for reduction(+:sum)
 for (int i=0;i<nsteps; ++i) {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 double pi = step * sum;
 auto t2 = clk::now();
 auto dif = duration_cast<microseconds>(t2-t1);
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Time= " << dif.count() << "us" << endl;
 return 0; 
}
Lab1/ej4/seq.cpp
#include <iostream>
#include <iomanip>
#include <chrono>
int main() {
 using namespace std;
 using namespace std::chrono;
 using clk = chrono::high_resolution_clock;
 
 auto t1 = clk::now();
 constexpr long nsteps = 10000000;
 double step = 1.0 / double(nsteps);
 double sum = 0.0;
 for (int i=0;i<nsteps; ++i) {
 double x = (i+0.5) * step;
 sum += 4.0 / (1.0 + x * x);
 }
 double pi = step * sum;
 auto t2 = clk::now();
 auto dif = duration_cast<microseconds>(t2-t1);
 cout << "PI= " << setprecision(10) << pi << endl;
 cout << "Time= " << dif.count() << "us" << endl;
 return 0; 
}
Arquitectura de Computadores/TEMA 3/Ejercicios ILP-ex-sol.pdf
Soluciones a ejercicios de Paralelismo a Nivel de instrucción
J. Daniel García Sánchez (coordinador)
David Expósito Singh
Javier García Blas
J. Manuel Pérez Lobato
Arquitectura de Computadores
Grupo ARCOS
Departamento de Informática
Universidad Carlos III de Madrid
1. Ejercicios de examen
Ejercicio 1 Examen de junio de 2015.
Considere un procesador tipo MIPS con arquitectura segmentada (pipeline) que tiene dos bancos
de registros separados uno para números enteros y otro para números en coma �otante. El banco de
registros enteros dispone de 32 registros. El banco de registros de coma �otante dispone de 16 registros
de doble precisión ($f0, $f2, . . . , $f30).
Se supone que se dispone de su�ciente ancho de banda de captación y decodi�cación como para
que no se generen detenciones por esta causa y que se puede iniciar la ejecución de una instrucción en
cada ciclo, excepto en los casos de detenciones debidas a dependencias de datos.
La siguiente tabla muestra las latencias adicionales de algunas categorías de instrucciones, en caso
de que haya dependencia de datos. Si no hay dependencia de datos la latencia no es aplicable.
Cuadro 1: Latencias adicionales por instrucción
Instrucción Latencia adicional Operación
ldc1
+2 Carga un valor de 64 bits en un registro de coma �otante.
sdc1
+2 Almacena un valor de 64 bits en memoria principal.
add.d
+4 Suma registros de coma �otante de doble precisión.
mul.d
+6 Multiplica registros de coma �otante de doble precisión.
addi
+0 Suma un valor a un registro entero.
subi
+0 Resta un valor a un registro entero.
bnez
+1 Salta si el valor de un registro no es cero.
La instrucción bnez usa bifurcación retrasada con una ranura de retraso (delay slot).
En esta máquina se desea ejecutar el siguiente código:
J. Daniel Garcia et al.
cbed ARCOS@uc3m
1 Arquitectura de Computadores
buc le : ldc1 $f0 , ($t0 )
ldc1 $f2 , ($t1 )
add.d $f4 , $f0 , $ f2
mul.d $f4 , $f4 , $ f6
sdc1 $f4 , ($t2 )
addi $t0 , $t0 , 8
addi $t1 , $t1 , 8
subi $t3 , $t3 , 1
bnez $t3 , buc le
addi $t2 , $t2 , 8
Inicialmente los valores de los registros son:
$t0: 0x00100000.
$t1: 0x00140000.
$t2: 0x00180000.
$t3: 0x00000100.
Se pide:
1. Enumere las dependencias de datos RAW que hay en el código anterior.
2. Indique todas las detenciones que se producen al ejecutar una iteración del código anterior, e
indique el número total de ciclos por iteración.
3. Intente plani�car el bucle para reducir el número de detenciones.
4. Desenrolle el bucle de manera que en cada iteración se procesen cuatro posiciones de los arrays
y determine el speedup conseguido. Utilice nombres de registros reales ($f0, $f2, . . . , $f30).
IMPORTANTE: Se considerarán incorrectas soluciones que no usen registros realmente existentes
(p. ej. $f2' o $f2� son nombres no válidos).
Solución 1
Depenencias Si se numeran las instrucciones consecutivamente comenzando en I1 (hasta I10), se
pueden identi�car las siguientes dependencias RAW:
1. $f0: I1 → I3.
2. $f2: I2 → I3.
3. $f4: I3 → I4.
4. $f4: I4 → I5.
5. $t3: I8 → I9.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
2 Arquitectura de Computadores
Detenciones A continuación se indican las detenciones que se producen al ejecutar el código:
ldc1 $f0 , ($t0 ) #I1
ldc1 $f2 , ($t1 ) #I2
<s t a l l > x 2
add.d $f4 , $f0 , $ f2 #I3
<s t a l l > x 4
mul.d $f4 , $f4 , $ f6 #I4
<s t a l l > x 6
sdc1 $f4 , ($t2 ) #I5
addi $t0 , $t0 , 8 #I6
addi $t1 , $t1 , 8 #I7
subi $t3 , $t3 , 1 #I8
bnez $t3 , buc le #I9
addi $t2 , $t2 , 8 #I10
En total se requieren 22 ciclos.
Plani�cación de bucle Si se reordenan las instrucciones se puede reducir el número de detenciones:
ldc1 $f0 , ($t0 ) #I1
ldc1 $f2 , ($t1 ) #I2
addi $t0 , $t0 , 8 #I6
addi $t1 , $t1 , 8 #I7
add.d $f4 , $f0 , $ f2 #I3
subi $t3 , $t3 , 1 #I8
<s t a l l > x 3
mul.d $f4 , $f4 , $ f6 #I4
<s t a l l > x 6
sdc1 $f4 , ($t2 ) #I5
bnez $t3 , buc le #I9
addi $t2 , $t2 , 8 #I10
En
total se requieren 19 ciclos.
Bucle desenrollado Al desenrollar el bucle con un factor de cuatro se obtiene.
ldc1 $f0 , ($t0 )
ldc1 $f2 , ($t1 )
ldc1 $f8 , 8($t0 )
ldc1 $f10 , 8($t1 )
ldc1 $f14 , 16($t0 )
ldc1 $f16 , 16($t1 )
ldc1 $f20 , 24($t0 )
ldc1 $f22 , 24($t1 )
add.d $f4 , $f0 , $ f2
add.d $f12 , $f8 , $ f10
add.d $f18 , $f14 , $ f16
add.d $f24 , $f20 , $ f22
<s t a l l >
mul.d $f4 , $f4 , $ f6
mul.d $f12 , $f12 , $ f6
mul.d $f18 , $f18 , $ f6
mul.d $f24 , $f24 , $ f6
addi $t0 , 32
addi $t1 , 32
<s t a l l >
sdc1 $f4 , ($t2 )
sdc1 $f12 , 8($t2 )
sdc1 $f18 , 16($t2 )
sdc1 $f24 , 24($t2 )
subi $t3 , 4
bnez $t3 , buc le
addi $t2 , 32
En total se requieren 27 ciclos cada 4 iteraciones. Esto es 6,75 ciclos por iteración
Ejercicio 2 Examen de enero de 2015.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
3 Arquitectura de Computadores
Sea el siguiente fragmento de código se encuentra almacenado a partir de la dirección de memoria
0x1000100C en una máquina en la que todas las instrucciones ocupan 4 bytes:
buc le : lw $r2 , 0( $r0 )
addi $r3 , $r2 , 20
sw $r3 , 0( $r1 )
addi $r0 , $r0 , 4
addi $r1 , $r1 , 4
bnez $r2 , buc le
Dicho código se ejecuta en una máquina que dispone de una caché L1 para datos asociativa por
conjuntos de 2 vías y con un tamaño de 32 KB y una caché L1 para instrucciones de iguales caracte-
rísticas. También dispone de una caché L2 uni�cada asociativa por conjuntos de 8 vías con un tamaño
de 1 MB. En ambos casos el tamaño de línea es de 32 bytes. Se asume que un acierto en la caché
L1 requiere 4 ciclos, y un acierto en la caché L2 requiere 14 ciclos adicionales y la penalización por
traer un bloque de memoria principal a la caché de nivel 2 es de 80 ciclos. Todas las cachés tienen una
política de escritura write-back.
Inicialmente el valor de los registros es:
$r0: 0x00010000.
$r1: 0x00080000.
A partir de la posición 0x00010000 todos los valores en memoria son distintos de cero hasta la
posición 0x000100FC. En la posición de memoria 0x000100FC hay un valor de cero.
1. Determine cuál debería ser el tiempo medio de acceso asumiendo que un programa (distinto del
facilitado) realiza en promedio 2 accesos a datos por instrucción y tiene las siguientes tasas de
fallo:
L1 instrucciones: 10%
L1 datos: 5%
L2: 2%
2. Determine el número de fallos que se producen durante la ejecución del fragmento de código
facilitado en el enunciado para las cachés L1 de datos, L1 de instrucciones y L2.
3. 1.3: Elabore un diagrama de tiempos para una arquitectura MIPS con un pipeline de 5 etapas
para la primera iteración del bucle asumiendo que inicialmente no hay datos ni instrucciones en
las cachés y con las siguientes consideraciones:
No hay hardware de forwarding.
La arquitectura permite que una instrucción escriba en un registro y otra instrucción lea
ese mismo registro sin problemas.
Las bifurcaciones se tratan vaciando el pipeline.
La dirección efectiva de salto se calcula en la etapa de ejecución.
NOTA: Tenga en cuenta en el cronograma las detenciones debidas a los fallos en toda la jerarquía
de caché tanto para instrucciones (etapa IF) como para lecturas y escrituras de datos (etapa M).
4. Repita el diagrama de tiempos para la segunda iteración.
Solución 2
J. Daniel Garcia et al.
cbed ARCOS@uc3m
4 Arquitectura de Computadores
Tiempo medio de acceso En cuanto a los accesos a la caché de nivel 1, se tiene que se realiza 2
accesos a datos por cada acceso a instrucciones. Por tanto la tasa de fallos se obtiene mediante media
ponderanda:
mL1 =
mL1I + 2 ·mL1D
3
mL1 =
0,1 + 2 · 0,05
3
=
0,2
3
= 0,0667
Por tanto el tiempo medio de acceso sería:
T = 4 +mL1 · (14 +mL2 · 80) = 4 + 0,0667 · (14 + 0,02 · 80) = 5,04 ciclos
Número de fallos El bucle se ejecuta un total de 2
8
4 = 2
6 = 64 iteraciones.
Analizaremos por separado los accesos de instrucciones y datos.
La primera instrucción se almacena en la dirección 0x1000100C. La última instrucción se almacena
en la dirección en la dirección 0x1000100C +(6− 1) ∗ 4 = 0x10001020.
En la primera iteración, la primera instrucción genera un fallo de caché y trae el bloque de direccio-
nes 0x10001000 � 0x1000101F, que contiene una instrucción de interés. Las siguientes instrucciones
(I2, I3, I4, e I5) generan aciertos. Por último, la instrucción I6 vuelve a generar un fallo. Por tanto,
la primera iteración genera 2 fallos y 4 aciertos. El resto de iteraciones generan aciertos en todos los
casos.
Como el bucle se ejecuta 64 veces, el acceso a las instrucciones genera los siguientes accesos:
Fallos L1I: 2
Aciertos L1I: 4 + 63 · 6
Fallos L2: 1
Aciertos L2: 0
En cada iteración del bucle se lee una dirección de memoria en el rango 0x00010000 � 0x000100FC.
Esto se corresponde con 2
8
25
= 8 líneas de caché.
Igualmente se escriben valores en las direcciones 0x00080000 � 0x000800FC, que se escriben en
8 líneas de la caché. Como las cachés son asociativas por conjuntos no se dan con�ictos entre los datos
leídos y escritos. Como no se expulsa ninguna línea de la caché L1 no hay escrituras en la caché L2.
1. Fallos L1D: 8 lecturas + 8 escrituras
2. Aciertos L1D: 56 lecturas + 56 escrituras
3. Fallos L2: 8 lecturas
4. Aciertos L2: 0
J. Daniel Garcia et al.
cbed ARCOS@uc3m
5 Arquitectura de Computadores
Diagrama de tiempos para primera iteración Si se numeran las instrucciones de la siguiente
forma:
buc le : lw $r2 , 0( $r0 ) #1
addi $r3 , $r2 , 20 #2
sw $r3 , 0( $r1 ) #3
addi $r0 , $r0 , 4 #4
addi $r1 , $r1 , 4 #5
bnez $r2 , buc le #6
Se tienen las siguientes dependencias RAW:
1. $r2: I2 → I1
2. $r3: I3 → I2
3. $r0: I4 → I1
4. $r1: I3 → I5
Al no haber forwarding, cuando hay una dependencia RAW debe esperarse al ciclo WB de la
instrucción fuente para inicial el ciclo de la instrucción destino. La Tabla 2 muestra el correspondiente
diagrama de tiempos.
La primera instrucción se detiene 98 ciclos (80+14+4) en el fetch por ser un fallo en toda la
jerarquía de memoria.
La lectura de datos de la primera instrucción es un fallo de lectura y requiere 98 ciclos también.
La segunda instrucción es un acierto y requiere cuatro ciclos para realizar la captación de la caché
L1I.
La instrucción I3 es un acierto y requiere cuatro ciclos para realizar la captación de la caché L1I.
La escritura de datos de la instrucción I3 es un fallo de escritura y requiere 98 ciclos.
La instrucción I4 es un acierto y requiere cuatro ciclos para realizar la captación de la caché L1I.
La instrucción I4 no puede iniciar su ciclo de memoria hasta que no termine el acceso a memoria
de I3.
La instrucción I5 es un acierto y requiere cuatro ciclos para realizar la captación de L1I.
La instrucción I5 no puede iniciar su ciclo de ejecución hasta que no termine la ejecución de I4.
La instrucción I6 es un fallo y requiere 98 ciclos para realizar la captación de L1I.
La instrucción I7 (la siguiente a la bnez) no puede comenzar la captación hasta que no se libera
la unidad de fetch.
Si bien se conoce la dirección de salto al �nal de la etapa de decodi�cación de I6, el sentido de
salto (tomar o no tomar) no se conoce hasta el �nal de la etapa de ejecución.
En total se requieren 310 ciclos.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
6 Arquitectura de Computadores
In
st
ru
c
c
ió
n
1�
98
99
10
0
10
1
10
2
10
3�
19
8
19
9
20
0
20
1
20
2
20
3
20
4
20
5
20
6
20
7
20
8
20
9
21
0
I1
:
lw
$
r2
,
0
($
r0
)
IF
ID
E
X
M
M
M
W
B
I2
:
a
d
d
i
$
r3
,
$
r2
,
2
0
IF
1
IF
2
IF
3
IF
4
�
ID
E
X
M
W
B
I3
:
sw
$
r3
,
0
($
r1
)
IF
1
IF
2
IF
3
IF
4
ID
E
X
M
M
M
M
M
M
I4
:
a
d
d
i
$
r0
,
$
r0
,
4
IF
1
IF
2
IF
3
IF
4
ID
E
X
�
�
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
1
IF
2
IF
3
IF
4
In
st
ru
c
c
ió
n
21
1
21
2
21
3
21
4
21
5�
30
2
30
3
30
4
30
5
30
6
30
7
30
8
30
9
31
0
31
1
31
2
I1
:
lw
$
r2
,
0
($
r0
)
I2
:
a
d
d
i
$
r3
,
$
r2
,
2
0
I3
:
sw
$
r3
,
0
($
r1
)
M
M
M
M
M
W
B
I4
:
a
d
d
i
$
r0
,
$
r0
,
4
�
�
�
�
�
M
W
B
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
ID
�
�
�
�
E
X
M
W
B
I6
:
b
n
e
z
$
r2
,
b
u
c
le
IF
IF
IF
IF
IF
IF
IF
IF
IF
IF
IF
ID
E
X
M
I7
:
?
IF
�u
sh
I1
:
lw
$
r2
,
0
($
r0
)
IF
C
ua
dr
o
2:
D
ia
gr
am
a
de
ti
em
p
os
de
la
pi
m
er
a
it
er
ac
ió
n
de
l
ej
er
ci
ci
o
2.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
7 Arquitectura de Computadores
In
stru
c
c
ió
n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
I1
:
lw
$
r2
,
0
($
r0
)
IF
IF
IF
IF
ID
E
X
M
M
M
M
W
B
I2
:
a
d
d
i
$
r3
,
$
r2
,
2
0
IF
IF
IF
IF
�
�
ID
E
X
M
W
B
I3
:
sw
$
r3
,
0
($
r1
)
IF
IF
IF
IF
ID
E
X
M
M
M
M
W
B
I4
:
a
d
d
i
$
r0
,
$
r0
,
4
IF
IF
IF
IF
ID
E
X
M
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
IF
IF
In
stru
c
c
ió
n
22
23
24
25
26
27
28
29
30
I1
:
lw
$
r2
,
0
($
r0
)
I2
:
a
d
d
i
$
r3
,
$
r2
,
2
0
I3
:
sw
$
r3
,
0
($
r1
)
I4
:
a
d
d
i
$
r0
,
$
r0
,
4
W
B
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
ID
E
X
M
W
B
I6
:
b
n
e
z
$
r2
,
b
u
c
le
IF
IF
IF
IF
ID
E
X
M
W
B
I7
:
?
IF
�ush
I1
:
lw
$
r2
,
0
($
r0
)
IF
C
uadro
3:
D
iagram
a
de
tiem
p
os
de
la
segunda
iteración
del
ejercicio
2.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
8 Arquitectura de Computadores
Diagrama de tiempos para segunda iteración La Tabla 3 muestra el correspondiente diagrama
de tiempos. En total se requieren 28 ciclos de reloj.
Ejercicio 3 Examen de octubre de 2014.
Sea el siguiente fragmento de código:
buc le : lw $f0 , 0( $r1 )
lw $f2 , 0( $r2 )
mul . f $f4 , $f0 , $ f2
add.d $f6 , $f6 , $ f4
addi $r1 , $r1 , 4
addi $r2 , $r2 , 4
sub $r3 , $r3 , 1
bnez $r3 , buc le
1. Haga una lista con todas las posibles dependencia de datos, sin considerar una estructura espe-
cí�ca de la arquitectura segmentada. Para cada dependencia debe indicar, registro, instrucción
de origen, instrucción de destino y tipo de dependencia.
2. Elabore un diagrama de tiempos para una arquitectura MIPS con un pipeline en 5 etapas, con
las siguientes consideraciones:
No hay hardware de forwarding.
La arquitectura permite que una instrucción escriba en un registro y otra instrucción lea
ese mismo registro sin problemas.
Las bifurcaciones se tratan vaciando el pipeline.
Las referencias a memoria requieren un ciclo de reloj.
La dirección efectiva de salto se calcula en la etapa de ejecución.
3. Determine cuantos ciclos se necesitan para ejecutar N iteraciones del bucle.
4. Elabore un diagrama de tiempos para una arquitectura MIPS con un pipeline en 5 etapas con
las siguientes consideraciones:
Hay hardware completo de forwarding.
Asuma que las bifurcaciones se tratan prediciendo todos los saltos como tomados.
5. Determine cuantos ciclos se necesitan para ejecutar N iteraciones del bucle en las condiciones del
apartado 4.
Solución 3
Dependencias de datos Si se numeran las instrucciones desde I1 (primera instrucción) hasta I8
(última instrucción) se tienen las siguientes dependencias:
$f0: I1 → I3 (RAW)
$f2: I2 → I3 (RAW)
$f4: I3 → I4 (RAW)
$r3: I7 → I8 (RAW)
J. Daniel Garcia et al.
cbed ARCOS@uc3m
9 Arquitectura de Computadores
In
stru
c
c
ió
n
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
I1
:
lw
$
f0
,
0($
r1
)
ID
ID
E
X
M
W
B
I2
:
lw
$
f2
,
0($
r2
)
IF
ID
E
X
M
W
B
I3
:
m
u
l.f
$
f4
,
$
f0
,
$
f2
IF
�
�
ID
E
X
M
W
B
I4
:
a
d
d
.d
$
f6
,
$
f6
,
$
f4
IF
�
�
ID
E
X
M
W
B
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
ID
E
X
M
W
B
I6
:
a
d
d
i
$
r2
,
$
r2
,
4
IF
ID
E
X
M
W
B
I7
:
su
b
$
r3
,
$
r3
,
1
IF
ID
E
X
M
W
B
I8
:
b
n
e
z
$
r3
,
b
u
c
le
IF
�
�
ID
E
X
M
W
B
I9
:
(sig
a
b
n
e
z)
IF
I1
:
lw
$
f0
,
0
($
r1
)
IF
ID
E
X
M
W
B
C
uadro
4:
P
rim
er
diagram
a
de
tiem
p
os
del
ejercicio
3.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
10 Arquitectura de Computadores
Primer diagrama de tiempos Al no haber forwarding, cuando hay una dependencia RAW debe
esperarse al ciclo WB de la instrucción fuente para inicial el ciclo de la instrucción destino. La Tabla 4
muestra el correspondiente diagrama de tiempos.
La instrucción I3, tiene una detención hasta que I2 haya escrito el valor leído en $f2. Se puede
realizar la lectura de banco de registros en el mismo ciclo en que I2 escribe en el banco de registros
(ciclo 6).
La instrucción I4 no puede comenzar la captación hasta que no se libera la unidad de fetch (ciclo
6).
La instrucción I4, tiene una detención hasta que I3 haya escrito el valor calculado en $f4. Se
puede realizar la lectura de banco de registros en el mismo ciclo en que I3 escribe en el banco de
registros (ciclo 9).
La instrucción I5 no puede comenzar la captación hasta que no se libere la unidad de fetch (ciclo
9).
La instrucción I8 tiene una detención hasta que I7 haya escrito el valor $r3. Se puede realizar la
lectura de banco de registros en el mismo ciclo en que I7 escribe en el banco de registros (ciclo
15).
La instrucción I9 (la siguiente a la bnez) no puede comenzar la captación hasta que no se libera
la unidad de fetch (ciclo 15).
Si bien se conoce la dirección de salto al �nal de la etapa de decodi�cación de I8, el sentido
de salto (tomar o no tomar) no se conoce hasta el �nal de la etapa de ejecución Por tanto la
captación se repite en el ciclo 17.
Primera estimación de ciclos Para determinar el número de ciclos se debe determinar, cuántos
ciclos se requieren para cualquier iteración y cuántos para la última iteración.
El coste de una iteración distinta de la última se obtiene determinando el número de ciclos desde
que se inicia la ejecución de I1 hasta que esta se vuelve a iniciar. Esto son 16 ciclos.
El coste de la última iteración se obtiene determinando el número de ciclos hasta que se �naliza la
ejecución de la instrucción I8. Estos son 18 ciclos.
Coste = 16 · n+ 2
.
Segundo diagrama de tiempos Ahora se permite forwarding siempre que sea posible y no hay
que esperar a la etapa de WB. La Tabla 5 muestra el correspondiente diagrama de tiempos.
La instrucción I3 puede iniciar ejecución tras la etapa de memoria de I2 (ciclo 6) gracias al
forwarding.
La instrucción I4 no puede iniciar la decodi�cación hasta que no se ha liberado la unidad de
decodi�cación (ciclo 6).
La instrucción I4 puede iniciar ejecución tras la etapa de ejecución de I3 (ciclo 7) gracias al
forwarding.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
11 Arquitectura de Computadores
In
stru
c
c
ió
n
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
I1
:
lw
$
f0
,
0($
r1
)
ID
ID
E
X
M
W
B
I2
:
lw
$
f2
,
0($
r2
)
IF
ID
E
X
M
W
B
I3
:
m
u
l.f
$
f4
,
$
f0
,
$
f2
IF
ID
�
E
X
M
W
B
I4
:
a
d
d
.d
$
f6
,
$
f6
,
$
f4
IF
�
ID
E
X
M
W
B
I5
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
ID
E
X
M
W
B
I6
:
a
d
d
i
$
r2
,
$
r2
,
4
IF
ID
E
X
M
W
B
I7
:
su
b
$
r3
,
$
r3
,
1
IF
ID
E
X
M
W
B
I8
:
b
n
e
z
$
r3
,
b
u
c
le
IF
ID
E
X
M
W
B
I1
:
lw
$
f0
,
0
($
r1
)
IF
ID
E
X
M
W
B
C
uadro
5:
Segundo
diagram
a
de
tiem
p
os
del
ejercicio
3.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
12 Arquitectura de Computadores
La instrucción I5 no puede iniciar la captación hasta que no se libera la unidad de fetch (ciclo
6).
La instrucción I8 no puede iniciar la decodi�cación hasta que no se ha calculado el valor de $r3
(ciclo 10) y se le pasa mediante forwarding (ciclo 11).
Segunda estimación de ciclos El coste de una iteración distinta de la última es de 10 ciclos. La
última iteración requiere 14 ciclos.
Coste = 10 · n+ 4
Ejercicio 4 Octubre de 2014.
Sea el siguiente fragmento de código:
buc le : lw $f0 , 0( $r1 )
lw $f2 , 0( $r2 )
s ub . f $f4 , $f0 , $ f2
mul.d $f4 , $f4 , $ f4
add.d $f6 , $f6 , $ f4
addi $r1 , $r1 , 4
addi $r2 , $r2 , 4
sub $r3 , $r3 , 1
bnez $r3 , buc le
1. Haga una lista con toda la posible dependencia de datos, sin considerar una estructura especí�ca
de la arquitectura segmentada. Para cada dependencia debe indicar, registro, instrucción de
origen, instrucción de destino y tipo de dependencia.
2. Elabore un diagrama de tiempos para una arquitectura MIPS con un pipeline en 5 etapas, con
las siguientes consideraciones:
No hay hardware de forwarding.
La arquitectura permite que una instrucción escriba en un registro y otra instrucción lea
ese mismo registro sin problemas en el mismo ciclo de reloj.
Las bifurcaciones se tratan vaciando el pipeline.
Las referencias a memoria requieren un ciclo de reloj.
La dirección efectiva de salto se calcula en la etapa de ejecución.
3. Determine cuantos ciclos se necesitan para ejecutar N iteraciones del bucle.
4. Elabore un diagrama de tiempos para una arquitectura MIPS con un pipeline en 5 etapas con
las siguientes consideraciones:
Hay hardware completo de forwarding.
Asuma que las bifurcaciones se tratan prediciendo todos los saltos como tomados.
5. Determine cuantos ciclos se necesitan para ejecutar N iteraciones del bucle en las condiciones del
apartado 4.
Solución 4
J. Daniel Garcia et al.
cbed ARCOS@uc3m
13 Arquitectura de Computadores
Depdencias de datos Si se numeran las instrucciones desde I1 (primera instrucción) hasta I9
(última instrucción) se tienen las siguientes dependencias:
$f0: I1 → I3 (RAW)
$f2: I2 → I3 (RAW)
$f4: I3 → I4 (RAW, WAW)
$f4: I4 → I5 (RAW)
$r3: I8 → I9 (RAW)
Primer diagrama de tiempos Al no haber forwarding, cuando hay una dependencia RAW debe
esperarse al ciclo WB de la instrucción fuente para inicial el ciclo de la instrucción destino. La Tabla 6
muestra el correspondiente diagrama de tiempos.
La instrucción I3, tiene una detención hasta que I2 haya escrito el valor leído en $f2. Se puede
realizar la lectura de banco de registros en el mismo ciclo en que I2 escribe en el banco de registros
(ciclo 6).
La instrucción I4 no puede comenzar la captación hasta que no se libera la unidad de fetch (ciclo
6).
La instrucción I4, tiene una detención hasta que I3 haya escrito el valor calculado en $f4. Se
puede realizar la lectura de banco de registros en el mismo ciclo en que I3 escribe en el banco de
registros (ciclo 9).
La instrucción I5 no puede comenzar la captación hasta que no se libere la unidad de fetch (ciclo
9).
La instrucción I5, tiene una detención hasta que I4 haya escrito el valor calculado de $f4. Se
puede realizar la lectura de banco de registros en el mismo ciclo en que I4 escribe en el banco de
registros (ciclo 12).
La instrucción I6 no puede comenzar la captación hasta que no se libere la unidad de fetch (ciclo
12).
La instrucción I9 tiene una detención hasta que I8 haya escrito el valor $r3. Se puede realizar la
lectura de banco de registros en el mismo ciclo en que I7 escribe en el banco de registros (ciclo
18).
La instrucción I10 (la siguiente a la bnez) no puede comenzar la captación hasta que no se libera
la unidad de fetch (ciclo 18).
Si bien se conoce la dirección de salto al �nal de la etapa de decodi�cación de I9, el sentido
de salto (tomar o no tomar) no se conoce hasta el �nal de la etapa de ejecución Por tanto la
captación se repite en el ciclo 20.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
14 Arquitectura de Computadores
In
st
ru
c
c
ió
n
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
I1
:
lw
$
f0
,
0(
$
r1
)
IF
ID
E
X
M
W
B
I2
:
lw
$
f2
,
0
($
r2
)
IF
ID
E
X
M
W
B
I3
:
su
b
.f
$
f4
,
$
f0
,
$
f2
IF
�
�
ID
E
X
M
W
B
I4
:
m
u
l.
d
$
f4
,
$
f4
,
$
f4
IF
�
�
ID
E
X
M
W
B
I5
:
a
d
d
.d
$
f6
,
$
f6
,
$
f4
IF
�
�
ID
E
X
M
W
B
I6
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
ID
E
X
M
W
B
I7
:
a
d
d
i
$
r2
,
$
r2
,
4
IF
ID
E
X
M
W
B
I8
:
su
b
$
r3
,
$
r3
,
4
IF
ID
E
X
M
W
B
I9
:
b
n
e
z
$
r3
,
b
u
c
le
IF
�
�
ID
E
X
M
W
B
I1
0
:
(s
ig
ui
en
te
a
b
n
e
z
)
IF
�
I1
:
lw
$
f0
,
0(
$
r1
)
IF
ID
C
ua
dr
o
6:
P
ri
m
er
di
ag
ra
m
a
de
ti
em
p
os
de
l
ej
er
ci
ci
o
4.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
15 Arquitectura de Computadores
Primera estimación de ciclos Para determinar el número de ciclos se debe determinar, cuántos
ciclos se requieren para cualquier iteración y cuántos para la última iteración.
El coste de una iteración distinta de la última se obtiene determinando el número de ciclos desde
que se inicia la ejecución de I1 hasta que esta se vuelve a iniciar. Esto son 19 ciclos.
El coste de la última iteración se obtiene determinando el número de ciclos hasta que se �naliza la
ejecución de la instrucción I9. Estos son 21 ciclos.
Coste = 19 · n+ 2.
Segundo diagrama de tiempos Ahora se permite forwarding siempre que sea posible y no hay
que esperar a la etapa de WB. La Tabla 7 muestra el correspondiente diagrama de tiempos.
La instrucción I3 puede iniciar ejecución tras la etapa de memoria de I2 (ciclo 6) gracias al
forwarding.
La instrucción I4 no puede iniciar la decodi�cación hasta que no se ha liberado la unidad de
decodi�cación (ciclo 6).
La instrucción I4 puede iniciar ejecución tras la etapa de ejecución de I3 (ciclo 7) gracias al
forwarding.
La instrucción I5 no puede iniciar la captación hasta que no se libera la unidad de fetch (ciclo
6).
La instrucción I5 puede iniciar ejecución tras la etapa de ejecución de I4 (ciclo 8) gracias al
forwarding.
La instrucción I9 no puede iniciar la decodi�cación hasta que no se ha calculado el valor de $r3
(ciclo 11) y se le pasa via forwarding (ciclo 12).
Segunda estimación de ciclos El coste de una iteración distinta de la última es de 11 ciclos. La
última iteración requiere 15 ciclos.
Coste = 11 · n+ 4
Ejercicio 5 Examen de junio de 2014.
En un determinado procesador se dispone de la tabla 8 de latencia entre instrucciones:
En esta máquina se desea ejecutar el siguiente trozo de código:
BUCLE: L.D F0 , 0(R1)
L.D F2 , 0(R2)
ADD.D F4 , F0 , F2
S.D F4 , 0(R3)
DADDUI R1 , R1 , #−8
BNE R1 , R4 , BUCLE
Inicialmente se tienen los siguientes valores:
R1: Último elemento de primer array origen.
R2: Último elemento de segundo array origen.
R3: Último elemento de array destino.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
16 Arquitectura de Computadores
In
st
ru
c
c
ió
n
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
I1
:
lw
$
f0
,
0(
$
r1
)
IF
ID
E
X
M
W
B
I2
:
lw
$
f2
,
0
($
r2
)
IF
ID
E
X
M
W
B
I3
:
su
b
.f
$
f4
,
$
f0
,
$
f2
IF
�
ID
E
X
M
W
B
I4
:
m
u
l.
d
$
f4
,
$
f4
,
$
f4
IF
�
ID
E
X
M
W
B
I5
:
a
d
d
.d
$
f6
,
$
f6
,
$
f4
IF
ID
E
X
M
W
B
I6
:
a
d
d
i
$
r1
,
$
r1
,
4
IF
ID
E
X
M
W
B
I7
:
a
d
d
i
$
r2
,
$
r2
,
4
IF
ID
E
X
M
W
B
I8
:
su
b
$
r3
,
$
r3
,
4
IF
ID
E
X
M
W
B
I9
:
b
n
e
z
$
r3
,
b
u
c
le
IF
�
ID
E
X
M
W
B
I1
:
lw
$
f0
,
0(
$
r1
)
IF
ID
E
X
M
W
B
C
ua
dr
o
7:
Se
gu
nd
o
di
ag
ra
m
a
de
ti
em
p
os
de
l
ej
er
ci
ci
o
4.
J. Daniel Garcia et al.
cbed ARCOS@uc3m
17 Arquitectura de Computadores
Cuadro 8: Latencia entre instrucciones
Instrucción que produce el resultado Instrucción que usa el resultado Latencia
Operación ALU FP Otra operación ALU FP 6
Operación ALU FP Almacenar doble 3
Cargar doble Operación ALU FP 2
Cargar doble Almacenar doble 0
R4: Precalculado. Tal que 8(R4) sea el primer elemento del primer array origen.
Todos los arrays tienen un tamaño de 4000 elementos.
Se pide:
1. Determine cuántos ciclos se requiere para ejecutar todas las iteraciones del bucle si no se realiza
ninguna modi�cación.
2. Determine cuántos ciclos se requiere para ejecutar todas las iteraciones si se realiza plani�cación
del bucle.
3. Determine cuántos ciclos se requiere para ejecutar todas las iteraciones si se desenrolla el bucle
para cada dos iteraciones.
4. Determine cuántos ciclos se requiere para ejecutar todas las iteraciones si se desenrolla el bucle
para cada cuatro iteraciones.
Solución 5
Apartado 1 La ejecución de una iteración del bucle sería:
L.D F0 , 0(R1)
L.D F2 , 0(R2)
<s t a l l > x 2
ADD.D F4 , F0 , F2
<s t a l l > x 3
S.D F4 , 0(R3)
DADDUI R1 , R1 , #−8
BNE R1 , R4 , BUCLE
En total cada iteración requiere 11 ciclos para haber iniciado todas las instrucciones. Lo que da
lugar a un total de 44,000 ciclos.
Apartado 2 La instrucción DADDUI podría adelantarse:
L.D F0 , 0(R1)
L.D F2 , 0(R2)
DADDUI R1 , R1 , #−8
<s t a l l > x 1
ADD.D F4 , F0 , F2
<s t a l l > x 3
S.D F4 , 0(R3)
BNE R1 ,

Continuar navegando