the sieve of eratosthenesjbarbosa/ensino/pdp/2006-2007/acetatos/a4_si… · the sieve of...

Post on 11-Nov-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

The Sieve of Eratosthenes

Jorge Barbosa

2

Objectivos

1. Análise de sistemas de distribuição de dados por blocos

• Função MPI_Bcast

• Análise de desempenho

3

Modelos Computacionais

ÍÍndicendiceAlgoritmo SequencialIdentificação de fontes de paralelismoPartição de dadosDesenvolvimento e análise do algoritmo paraleloPrograma MPIBenchmarkingOptimização

4

Algoritmo Sequencial

2 3 4 5 6 7 8 9 10 11 12 13 14 15 1617 18 19 20 21 22 23 24 25 26 27 28 29 30 3132 33 34 35 36 37 38 39 40 41 42 43 44 45 4647 48 49 50 51 52 53 54 55 56 57 58 59 60 61

2 4 6 8 10 12 14 1618 20 22 24 26 28 30

32 34 36 38 40 42 44 4648 50 52 54 56 58 60

3 9 1521 27

33 39 4551 57

525

3555

7

49

Complexidade: Θ(n ln ln n)

5

Pseudo-código

1. Criar a lista de números naturais 2, 3, …, n2. k ← 23. Repetir

(a) Marcar todos os múltiplos de k entre k2 e n(b) k ← número mais pequeno não marcado e > k

Até k2 > n4. Os números não marcados são números primos

6

Fontes de paralelismo

• Decomposição de Domínio– Dividir os dados em blocos– Associar processamento a cada bloco

• Uma tarefa básica por elemento do array

7

Tornar o ponto 3(a) Paralelo

Marcar todos os múltiplos de k entre k2 e n

for all j where k2 ≤ j ≤ n doif (j mod k == 0) then

mark j (j não é número primo)endif

endfor

8

Tornar o ponto 3(b) Paralelo

Determinar o menor número > k que não esteja marcado

Min-reduction (para determinar o menor número não marcado)

Broadcast (enviar o valor obtido para todos os processos)

9

Aglomeração de tarefas

• Objectivos:– Obter tarefas com granularidade adequada– Reduzir o custo de comunicação– Balanceamento da carga pelos processadores

10

Decomposição dos dados

• Cíclica– Fácil de encontrar o processador que detém um dado elemento– Para este problema resulta em load imbalance

• Por Blocos– Balanceamento de carga– Mais difícil de determinar a localização dos dados se n não for múltiplo

de p

11

Decomposição dos dados

• Balanceamento da carga quando n não é múltiplo de p

• Cada processo recebe ⎡n/p⎤ ou ⎣n/p⎦ elementos

• Obter expressões simples para:

– Determinar primeiro e último índice dado um processador

– Determinar o processador dado um índice

12

Método 1

• r = n mod p

• If r = 0, todos os blocos têm o mesmo tamanho

• Else

– Primeiros blocos r ficam com o tamanho ⎡n/p⎤

– Restantes blocos p-r ficam com o tamanho ⎣n/p⎦

13

Exemplos

17 elementos divididos por 7 processos

17 elementos divididos por 5 processos

17 elementos divididos por 3 processos

14

Método 1: Cálculos

• Primeiro elemento controlado pelo processo i

• Último elemento controlado pelo processo i

• Processo que controla o elemento j

⎣ ⎦ ),min(/ ripni +

⎣ ⎦ 1),1min(/)1( −+++ ripni

⎣ ⎦⎣ ⎦ ⎣ ⎦⎣ ⎦)//)(,)1//(max( pnrjpnj −+

15

Método 2

• “Espalha” os blocos maiores pelos processos• Primeiro elemento controlado pelo processo i

• Último elemento controlado pelo processo i

• Processo que controla o elemento j

⎣ ⎦pin /

⎣ ⎦ 1/)1( −+ pni

⎣ ⎦njp /)1)1(( −+

16

Exemplos

17 elementos divididos por 7 processos

17 elementos divididos por 5 processos

17 elementos divididos por 3 processos

17

Comparação dos métodos

24Primeiro índice

47Processo

46Último índice

Método 2Método 1Operações

Operação “floor” não incluída

Melhor

18

Aplicação método 2

• Ilustração do método 2 na divisão de 13 elementos por 5 processos

13(0)/ 5 = 0

13(1)/5 = 2

13(2)/ 5 = 5

13(3)/ 5 = 7

13(4)/ 5 = 10

processo

19

Macros para a Decomposição dos dados

#define BLOCK_LOW(id,p,n) ((i)*(n)/(p))

#define BLOCK_HIGH(id,p,n) \(BLOCK_LOW((id)+1,p,n)-1)

#define BLOCK_SIZE(id,p,n) \(BLOCK_LOW((id)+1)-BLOCK_LOW(id))

#define BLOCK_OWNER(index,p,n) \(((p)*(index)+1)-1)/(n))

20

Índices Locais vs. Globais

L 0 1

L 0 1 2

L 0 1

L 0 1 2

L 0 1 2

G 0 1 G 2 3 4

G 5 6

G 7 8 9 G 10 11 12

21

Acesso aos Elementos

• Programa Sequencialfor (i = 0; i < n; i++) {

…}

• Programa Paralelosize = BLOCK_SIZE (id,p,n);for (i = 0; i < size; i++) {

gi = i + BLOCK_LOW(id,p,n);…

}Índice i neste processo…

…Corresponde ao índice gi do programa sequencial

22

A Decomposição efectuada afecta a Implementação

• O maior valor usado como semente é √n

• O primeiro processo tem ⎣n/p⎦ elementos

• Terá todas as sementes se p < √n

• Como consequência será sempre o primeiro processo a transmitir a

semente

• Então não é necessária a operação de redução

23

Marcação rápida

• A decomposição por blocos permite usar o mesmo algoritmo usado na versão sequencial:

j, j + k, j + 2k, j + 3k, … (o processo contém lista sequencial)

em vez de

for all j in blockif j mod k = 0 then mark j (it is not a prime)

24

Desenvolvimento do algoritmo paralelo

1. Criar lista de números naturais não marcados 2, 3, …, n

2. k ← 2

3. Repeat

(a) Marca todos os múltiplos de k entre k2 e n

(b) k ← o mais pequeno numero por marcar > k

until k2 > m

4. Os números não marcados são primos

Cada processo cria a sua parte da listaTodos os processos fazem o ponto 2

Cada processo marca na sua sublista

Apenas Processo 0

(c) Processo 0 broadcasts k para os restantes

5. Redução para obter todos os números primos

25

Função MPI_Bcast

int MPI_Bcast (

void *buffer, /* Addr of 1st element */

int count, /* # elements to broadcast */

MPI_Datatype datatype, /* Type of elements */

int root, /* ID of root process */

MPI_Comm comm) /* Communicator */

MPI_Bcast (&k, 1, MPI_INT, 0, MPI_COMM_WORLD);

26

Análise de complexidade

• χ tempo necessário para marcar uma célula• Tempo de execução sequencial: χ n ln ln n• Número de broadcasts: √n / ln √n• Tempo de Broadcast : λ ⎡ log p ⎤• Tempo de execução total:

⎡ ⎤pnnpnn log)ln/(/lnln λχ +

27

Código (1/4)

#include <mpi.h>#include <math.h>#include <stdio.h>#include "MyMPI.h"#define MIN(a,b) ((a)<(b)?(a):(b))

int main (int argc, char *argv[]){

...MPI_Init (&argc, &argv);MPI_Barrier(MPI_COMM_WORLD);elapsed_time = -MPI_Wtime();MPI_Comm_rank (MPI_COMM_WORLD, &id);MPI_Comm_size (MPI_COMM_WORLD, &p);

if (argc != 2) {if (!id) printf ("Command line: %s <m>\n", argv[0]);MPI_Finalize(); exit (1);

}

28

Código (2/4)

n = atoi(argv[1]);low_value = 2 + BLOCK_LOW(id,p,n-1);high_value = 2 + BLOCK_HIGH(id,p,n-1);size = BLOCK_SIZE(id,p,n-1);proc0_size = (n-1)/p;if ((2 + proc0_size) < (int) sqrt((double) n)) {

if (!id) printf ("Too many processes\n");MPI_Finalize();exit (1);

}

marked = (char *) malloc (size);if (marked == NULL) {

printf ("Cannot allocate enough memory\n");MPI_Finalize();exit (1);

}

29

Código (3/4)

for (i = 0; i < size; i++) marked[i] = 0;if (!id) index = 0;prime = 2;do {

if (prime * prime > low_value)first = prime * prime - low_value;

else {if (!(low_value % prime)) first = 0;else first = prime - (low_value % prime);

}for (i = first; i < size; i += prime) marked[i] = 1;if (!id) {

while (marked[++index]);prime = index + 2;

}MPI_Bcast (&prime, 1, MPI_INT, 0, MPI_COMM_WORLD);

} while (prime * prime <= n);

30

Código (4/4)

count = 0;for (i = 0; i < size; i++)

if (!marked[i]) count++;MPI_Reduce (&count, &global_count, 1, MPI_INT, MPI_SUM,

0, MPI_COMM_WORLD);elapsed_time += MPI_Wtime();if (!id) {

printf ("%d primes are less than or equal to %d\n",global_count, n);

printf ("Total elapsed time: %10.6f\n", elapsed_time);}MPI_Finalize ();return 0;

}

31

Benchmarking

• Estimar o tempo de execução para o calculo de números primos até 100 milhões.

• Determinar χ = 85.47 nanosec• Executar a versão sequencial num dos processadores.

Tempo de execução de 24.90 s.logo χ = 24.90/(10^8 ln ln 10^8) = 85.47 ns

• Determinar λ, o tempo para um broadcast.• Executar sucessivamente vários broadcasts para 2, …, p

processadores.– Obtém-se por exemplo λ = 250 μsec

Tempo total estimado em segundos:

⎡ ⎤p./p. log271409024 +

32

Tempo de execução (seg)

4.222

4.687

5.159

5.993

7.055

9.039

13.011

24.900

Actual (seg)

2.23%

Erro

3.9278

4.3717

4.9646

5.7945

6.7684

8.8433

12.7212

24.9001

EstimadoProcessadores

33

Melhoramentos

• Apagar os números pares

– Reduz o número de cálculos para metade

– Liberta memória para valores elevados de n

• Cada processo determina os números primos que servem de semente

– Replicação da computação dos valores primos até √n

– Elimina o passo de broadcast

• Reorganização dos ciclos

– A troca dos ciclos, i.e. para um segmento do vector de dados procurar os múltiplos de todas as sementes até √n (sendo n relativo ao segmento actual), aumenta a ‘cache hit rate’ (i.e. reduz as falhas de cache)

34

Reorganização dos Ciclos

Cache hit rate

Mais falhas de cache

Melhor desempenho da cache

35

Comparação das 4 Versões

1.585

1.820

2.127

2.559

3.201

4.272

6.378

12.466

Sieve 3 Sieve 4

0.3422.8563.9278

0.3913.0594.3717

0.4563.2704.9646

0.5433.6525.7945

0.6794.0726.7684

0.9015.0198.8433

1.3306.60912.7212

2.54312.23724.9001

Procs Sieve 2Sieve 110-vezes menor

7-vezes menor

36

Sumário

• Sieve of Eratosthenes: a paralelização pela decomposição do domínio

• Comparação de duas distribuições

– Escolhida a que apresenta formulas mais simples

• A optimização considerada revelou-se importante para maximizar o desempenho sequencial (um processador)

top related