OpenMP. Slides baseados em tutorial de Tim Mattson da Intel

Documentos relacionados
Matheus S. Serpa, Vinícius G. Pinto, Philippe O. A. Navaux Contato: INTEL MODERN CODE PARTNER

Programação em Paralelo OpenMP

Introdução ao OpenMP

Introdução à OpenMP (Dia 1) Prof. Guido Araujo

INE 5645 PROGRAMAÇÃO PARALELA E DISTRIBUIDA PROVA 2 03/07/2017 ALUNO

Paralela e Distribuída. com o MPI e o OpenMP

INE 5645 PROGRAMAÇÃO PARALELA E DISTRIBUIDA PROVA 2 03/07/2017 ALUNO

Introdução OpenMP. Nielsen Castelo Damasceno

Sistemas Distribuídos e Paralelos

Programação Paralela e Distribuída (DCC/UFRJ)

Introdução à Programação Paralela com OpenMP: Além das Diretivas de Compilação

Paralelismo em Computadores com Tecnologia Multicore

OpenMP: Variáveis de Ambiente

PROGRAMAÇÃO. Programação paralela com o OpenMP Em paralelo

AULA 06: PROGRAMAÇÃO EM MÁQUINAS PARALELAS

Paralela e Distribuída. Memória Paralela com o OpenMP

Programação Concorrente e Paralela

Programação de Computadores I Introdução ao C PROFESSORA CINTIA CAETANO

Variáveis primitivas e Controle de fluxo

OpenMP. Mestrado em Ciência da Computação Introdução ao Processamento Paralelo e Distribuído Prof. Dr. Adenauer Corrêa Yamin Mestranda: Nelsi Warken

Mochila Binária com OpenMP

Linguagem C Princípios Básicos (parte 1)

Programação Concorrente e Paralela. Noemi Rodriguez

Conceitos básicos de programação

ponteiros INF Programação I Prof. Roberto Azevedo

Exclusão Mútua (mutex)

Introdução. Atributos em Java. Atributos. Acesso à atributos em Java. Atributo versus variável. Atributos, métodos e encapsulamento.

Linguagem de Programação III

Paralelismo de dados. (execução de simultaneidade) Tipo de arquitetura paralela SIMD. SIMD (Single Instruction Multiple Data)

Introdução à Programação. Operadores, Expressões Aritméticas e Entrada/Saída de Dados

SSC PROGRAMAÇÃO CONCORRENTE. Aula 06 Modelos de Programação Prof. Jó Ueyama e Julio Cezar Estrella

Fundamentos de Sistemas Operacionais

Seleção Múltipla Laços (while, do-while, for) AULA 05

Sincronização e comunicação entre entidades de processamento. Mutex Volnys Bernal 1. Tópicos. Exclusão Mútua (mutex) Exclusão Mútua (Mutex)

Prof. Silvana Rossetto 9 de julho de DCC/IM/UFRJ

Sistemas Operacionais: Sincronização entre processos

Linguagem Chapel. Walter Perez Urcia. Universidade de São Paulo Instituto de Matemática e Estadística Departamento de Ciências da Computação

ESTRUTURA COM DECISÃO COMPOSTA

Programação Concorrente. Prof. Hugo Vieira Neto

Revisão C++ - Parte 1

C++ - Funções. Forma geral das funções C++

Tipos Básicos. Operadores de Incremento e Decremento. Operador Sizeof. Estruturas de Dados Aula 2: Estruturas Estáticas

Módulo 1. Introdução. AEDS I C++ (Rone Ilídio)

Programação em Memória Partilhada com o OpenMP

OpenMP. Um método de paralelização para as linguagens Fortran, C, C++ para shared memory systems.

Programação Estruturada

Métodos Computacionais. Comandos Condicionais e de Repetição em C

Programação de Computadores I. Aula - Vetores. Professor Ilaim Costa Junior.

Transcrição:

OpenMP Slides baseados em tutorial de Tim Mattson da Intel

Modelo OpenMP Como as threads interagem? OpenMP é um modelo baseado em multithreading Threads se comunicam pelo compartilhamento de variáveis Compartilhamento de variáveis pode levar à condição de corrida: Condição de corrida: quando o resultado do programa muda se as threads são escalonadas de modo diferente Para controlar condições de corrida: Use sincronização para proteger conflitos de dados Sincronização é cara então: Tente mudar o modo como os dados são acessados para minimizar a necessidade de sincronização

Sincronização Sincronização: trazer todas as threads para um ponto bem definido e conhecido da execução Duas formas mais comuns de sincronização: Barreira: cada thread espera na barreira até todas as threads chegarem Exclusão mútua: define um bloco de código que só pode ser executado por uma thread de cada vez

Sincronização:Barreira Barreira: Cada thread espera até que todas as threads cheguem #pragma omp parallel { int id=omp_get_thread_num(); A[id] = big_calc1(id); #pragma omp barrier B[id] = big_calc2(id, A);

Sincronização: seção crítica Exclusão mútua: Somente uma thread pode entrar na seção crítica de cada vez float res; #pragma omp parallel { float B; int i, id, nthrds; id = omp_get_thread_num(); nthrds = omp_get_num_threads(); for(i=id;i<niters;i+=nthrds){ B = big_job(i); #pragma omp critical res += consume (B);

Sincronização: atomicidade Atomicidade provê exclusão mútua mas se aplica somente a uma localização da memória (atualização, leitura, escrita e captura) #pragma omp parallel { double tmp, B; B = DOIT(); tmp = big_ugly(b); #pragma omp atomic X +=tmp;

Programa sequencial Pi static long num_steps = 100000; double step; void main () { int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); pi = step * sum;

Exercício 1 Modifique o programa pi de modo que todas as threads criem uma variável escalar local que armazena a soma parcial e atualizem uma variável compartilhada somando o valor da variável local multiplicado pelo step Utilize o pragma critical

Exercício 1 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 int main () {double pi; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads); #pragma omp parallel { int i, id,nthrds;double x, sum; id = omp_get_thread_num(); nthrds = omp_get_num_threads(); for (i=id, sum=0.0;i< num_steps; i=i+nthrds){ x = (i+0.5)*step; sum += 4.0/(1.0+x*x); #pragma omp critical pi += sum * step;

Exercício 2 Modifique o programa pi de modo que todas as threads atualizem uma variável compartilhada somando o valor calculado em um step a esta variável compartilhada Utilize o pragma critical

Exercício 2 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 int main () {double pi; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads); #pragma omp parallel { int i, id,nthrds;double x; id = omp_get_thread_num(); nthrds = omp_get_num_threads(); for (i=id, sum=0.0;i< num_steps; i=i+nthrds){ x = (i+0.5)*step; #pragma omp critical pi += 4.0/(1.0+x*x); pi = pi * step;

Exercício 3 Refaça o exercício 1 usando o pragma atomic

Exercício 3 Refaça o exercício 1 usando o pragma atomic #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 int main () {double pi; step = 1.0/(double) num_steps; omp_set_num_threads(num_threads); #pragma omp parallel { int i, id,nthrds;double x, sum; id = omp_get_thread_num(); nthrds = omp_get_num_threads(); for (i=id, sum=0.0;i< num_steps; i=i+nthrds){ x = (i+0.5)*step; sum += 4.0/(1.0+x*x); #pragma omp atomic pi += sum * step;

SPMD vs. Divisão de trabalho Uma construção paralela cria um programa Single Program Multiple Data pois cada thread executa o mesmo código Como fazer com que threads executem partes diferentes do código? Construção de laço

Divisão de trabalho por laço Uma construção de laço para divisão de trabalho divide as iterações do laço entre as threads #pragma omp parallel { #pragma omp for for (I=0;I<N;I++){ NEAT_STUFF(I); A variável I é privativa a cada thread por default. Pode também usar a cláusula private(i)

Divisão de trabalho por laço Código sequencial for(i=0;i<n;i++){ a[i] = a[i] + b[i];

Divisão de trabalho por laço Código sequencial for(i=0;i<n;i++){ a[i] = a[i] + b[i]; Código com região paralela #pragma omp parallel { int id, i, Nthrds, istart, iend; id = omp_get_thread_num(); Nthrds = omp_get_num_threads(); istart = id * N / Nthrds; iend = (id+1) * N / Nthrds; if (id == Nthrds-1) iend = N; for(i=istart;i<iend;i++) { a[i] = a[i] + b[i];

Divisão de trabalho por laço Código sequencial for(i=0;i<n;i++){ a[i] = a[i] + b[i]; Código com região paralela #pragma omp parallel { int id, i, Nthrds, istart, iend; id = omp_get_thread_num(); Nthrds = omp_get_num_threads(); istart = id * N / Nthrds; iend = (id+1) * N / Nthrds; if (id == Nthrds-1) iend = N; for(i=istart;i<iend;i++) { a[i] = a[i] + b[i]; Código com região paralela e com divisão de trabalho por laço #pragma omp parallel #pragma omp for for(i=0;i<n;i++) { a[i] = a[i] + b[i];

Cláusula schedule A cláusula schedule afeta como as iterações do laço são mapeadas nas threads schedule(static [,chunk]) Reparte blocos de iterações de tamanho chunk para cada thread schedule(dynamic[,chunk]) Cada thread apanha um bloco de chunk iterações de uma fila até que as iterações acabem schedule(guided[,chunk]) As threads apanham dinamicamente blocos de iterações que começam grandes e vão diminuindo até o tamanho chunk à medida que a execução procede. schedule(runtime) O tipo de escalonamento e o tamanho do bloco são obtidos da variável de ambiente OMP_SCHEDULE ou da biblioteca de execução. schedule(auto) O escalonamento é feito pelo sistema de execução e não precisa ser nenhum dos acima

Combinação de região paralela e construção de laço double res[max]; int i; #pragma omp parallel { #pragma omp for for (i=0;i< MAX; i++) { res[i] = huge(); double res[max]; int i; #pragma omp parallel for for (i=0;i< MAX; i++) { res[i] = huge();

Redução double ave=0.0, A[MAX]; int i; for (i=0;i< MAX; i++) { ave + = A[i]; ave = ave/max; Os valores estão sendo acumulados em uma variável que é uma situação muito comum de acontecer e se chama redução A maioria dos ambientes de programação paralela incluem operações de redução

Redução Claúsula de redução: reduction (op : list) Pode ser usada em uma região paralela ou de divisão de trabalho: Uma cópia local das variáveis em list é feita e inicializada dependendo da operação op (0 para + ). Atualizações são feitas nas cópias locais Cópias locais são reduzidas em um único valor utilizando a operação op e combinadas com os valores originais das variáveis globais em list As variáveis na lista list devem ser compartilhadas na região paralela

Operações de Redução e valores iniciais Operador Valor inicial C/C++ only + 0 Operator Valor inicial * 1-0 & ~0 0 ^ 0 min max Maior número positivo Número mais negativo && 1 0

Exercício 4 Paralelize o programa sequencial PI com uma construção de laço modificando o mínimo possível o programa sequencial static long num_steps = 100000; double step; void main () { int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); pi = step * sum;

Exercício 4 #include <omp.h> static long num_steps = 100000; double step; int main () { int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; #pragma omp parallel { double x; #pragma omp for reduction(+:sum) for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); pi = step * sum;