25 de maio de 2012

Encontro 8 - Quicksort

Roteiro do Encontro


Ordenação Rápida - Quick Sort

A ordenação rápida (Quick Sort) se basei em um conceito simples de divisão e conquista. Possui inúmeras aplicações em diferentes estruturas que necessitam de ordenação, em nosso caso de estudo usaremos um arquivo binário gerado com um gerador de sequências. Ele irá gerar por padrão 1000 palavras de 8 caracteres  para que seja ordenadas pelo algoritmo Quick Sort. O objetivo será paralelizar a ordenação, fazendo com que possamos reduzir esse tempo de ordenação consideravelmente.

O algoritmo inicial utilizado para esse problema é o seguinte:

int main(void) {
char *keys;
long int N, i;

FILE *file;

if ((file = fopen("quicksort.in", "r")) == NULL) {
perror("quicksort.in");
exit(1);
}

fscanf(file, "%ld", &N);
keys = (char*) malloc(N * 8);
if (keys == NULL) {
perror("Memory allocation");
exit(EXIT_FAILURE);
}

for (i = 0; i < N; i++)
fscanf(file, "%s", keys + (i * 8));
fclose(file);
    
    qsort(keys, N, 8, (int(*)(const void *, const void *)) strcmp);

if ((file = fopen("quicksort.out", "w")) == NULL) {
perror("quicksort.out");
exit(1);
}

for (i = 0; i < N; i++)
fprintf(file, "%s\n", keys + (i * 8));

fclose(file);
free(keys);

return EXIT_SUCCESS;
}

Paralelização

Durante a reunião foram discutidas diferentes abordagem para a solução desse problema. Inicialmente foi sugerido a modificação de função de leitura e foram anotados resultados efetivos nessa modificação, porém ainda não atingindo o objetivo principal. A paralelização foi decidida e será implementada em uma reunião futura.

18 de maio de 2012

Encontro 7 - Métricas de Desempenho e Coleta de Dados

Roteiro do Encontro

  1. Atualizar o site. 
  2. SpeedUp. 
  3. Eficiência. 
  4. Execução e Coleta de dados.
  • Atualizar o Site
    No encontro de hoje começamos a criação e atualização deste site. Utilizando a plataforma Blogger do Google. 
  • SpeedUp
    Buscamos entender como medir o speedUp de um programa paralelo, que é dado pela seguinte formula:
    Fonte: Wikipédia
    Onde T1 é o tempo do programa sequencial e Tp é o tempo do programa em paralelo.
  • Eficiência
    Assim como para o speedup estudamos como calculamos a eficiência de um programa em paralelo.
  • Execução e coleta de dados
    Nesta etapa fizemos a execução dos problemas feitos nos encontros anteriores, coletamos os tempos e obtemos o speedup e a eficiência de cada um. Os dados estão nas postagens de cada encontro.

11 de maio de 2012

Encontro 6 - Encontrando o valor de Pi

Roteiro do Encontro

  • Implementação do Algoritmo de geração de valor aproximado de pi;
  • Paralelização do algoritmo de pi;
  • Execução e Coleta de Dados;

Implementação do Algoritmo

O algoritmo de cálculo de pi se baseia no seguinte enunciado:

   Uma forma de se calcular o valor aproximado de π é através do seguinte método:

  • Sub-escreva um círculo dentro de um quadrado;
  • Gere pontos randomicamente dentro do quadrado;
  • Determine o número de pontos dentro do quadrado que também estão no círculo;
  • Seja r o número de pontos no círculo dividido pelo número de pontos no quadrado;
  • π ~ 4.r
  • Note que quanto mais pontos forem gerados, melhor será a aproximação.
npoints = 10000
circle_count = 0
do j = 1,npoints
   generate 2 random numbers between 0 and 1
xcoordinate = random1;
   ycoordinate = random2
if (xcoordinate, ycoordinate) inside circle then
circle_count = circle_count + 1
end do
PI = 4.0*circle_count/npoints

Implementação Paralela, Execução e Coleta dos Dados

 A primeira versão paralela desenvolvida foi a seguinte:

---------------------------------------------------------------------------------------------------------------------------------------
npoints = 10000
circle_count = 0

#pragma omp parallel for private(x, y, npoints) reduction(+:circle_count)
   do j = 1,npoints
       generate 2 random numbers between 0 and 1
       x = random1;
       y = random2
       if (x, y) inside circle then
             circle_count = circle_count + 1
   end do
PI = 4.0*circle_count/npoints

---------------------------------------------------------------------------------------------------------------------------------------
As aplicações foram executadas sobre o ambiente de testecontendo o SO Ubuntu (kernel 3.2.0-23) rodando sob um computador com processador Intel Core i7 2630QM, 2.0~2.9 GHz.e 8Gb memória DDR3.  Para os testes foi utilizado número de pontos/iterações igual a 1000000 na aplicação acima e 1000000000 para o teste abaixo.
Analisando a tabela de eficiência e speedup do algoritmo acima, notamos que ao invés de obter aumento de desempenho, perdemos em desempenho. Porque?


Num Threads Tempo Eficiência SpeedUp
1 0,556 - -
2 4,596 0,024 0,1209747607
3 5,72 0,029 0,0972027972
4 6,443 0,03 0,0862952041
5 6,678 0,041 0,0832584606
6 7,623 0,0043 0,0729371638
7 7,717 0,005 0,0720487236
8 7,775 0,0057 0,071511254

A resposta está no manual da função de geração de números aleatórios rand();
Baseado nisso, desenvolvemos uma nova versão paralela, que pode ser visualizada no algoritmo abaixo:
---------------------------------------------------------------------------------------------------------------------------------------
 #pragma omp parallel for private(i) reduction(+:pi)
        for(i=0; i< NUM_PONTOS; i++){
                pi += 4.0/(4.0*i+1.0);
                pi -= 4.0/(4.0*i+3.0);
        }
---------------------------------------------------------------------------------------------------------------------------------------
A tabela abaixo nos mostra os resultados obtidos para a execução da aplicação acima em nosso ambiente de teste.


Num Threads Tempo Eficiência SpeedUp
1 15,825 - -
2 8,238 0,9604879825 1,920975965
3 5,727 0,9210756068 2,7632268203
4 4,35 0,9094827586 3,6379310345
5 4,837 0,654331197 3,2716559851
6 4,504 0,5855905861 3,5135435169
7 4,594 0,4921014988 3,4447104919
8 4,436 0,4459253832 3,5674030658