Anda di halaman 1dari 9

Relatório técnico: Programação Paralela -

Exemplo com Pthread

Edjalma Queiroz da Silva

Technical Report - RT-INF_002-16 - Relatório Técnico


September - 2016 - Setembro

The contents of this document are the sole responsibility of the authors.

O conteúdo do presente documento é de única responsabilidade dos autores.

Arquitetura de Computadores
FASAM
www.fasam.edu.br
Sumário
1 Apresentação do Problema 2

2 Programa: MergeSort sem Paralelismo 3

3 Programa: MergeSort com o recurso de paralelismo do Pthread 4

4 Apêndice 5
4.1 mergeSortComPthread.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1
Relatório técnico: Programação Paralela -
Exemplo com Pthread
Edjalma Queiroz da Silva ∗
edjalmaqs@gmail.com

1 Apresentação do Problema
Com base na implementação sequencial recursiva do algoritmo de ordenação merge sort
(ver pseudocódigo abaixo), faça uma adaptação no código para executar as subdivisões do pro-
blema em várias threads, explorando o paralelismo de arquiteturas multicore.
mergesort ( data ) {

i f d a t a tem p e l o menos d o i s e l e m e n t o s {

5 m e r g e s o r t ( m e t a d e e s q u e r d a de d a t a ) ;

m e r g e s o r t ( m e t a d e d i r e i t a de d a t a ) ;

merge ( ambas a s m e t a d e s em um v e t o r o r d e n a d o ) ;
10 }

Para a compilação e execução dos programas foi um utilizado o Sistema Operacional


Ubuntu 14.04 LTS, rodando com 16 Gb de memória RAM, na plataforma Intel Core i5 − 3470,
conforme a Figura 1.


Doutorando em Ciência da Computação, INF-UFG

2
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 3

Figura 1: Visão geral da configuração de hardware utilizada para a compilação e execução dos
teste.

2 Programa: MergeSort sem Paralelismo


Antes de paralelizar o algoritmo do MergeSort, fizemos a execução dele sem o uso de
recursos de paralelimos. É possível observar na Figura 2 que a execução do Merge Sort sem
o uso do paralelismo, para uma entrada de 10 × 1000 gasta cerca de 0, 012 segundos. Ao
aumentarmos o tamanho da entrada do problema em 10×, o tempo também aumenta em 10×
passando para 0, 11 segundos. Dessa forma, ao aumentarmos de 100×10.000 para 1000×10.000
o tempo de processamento sobe para 1, 34 segundos, evidenciando o crescimento proporcional
ao tamanho da entrada para o problema de Busca e Ordenação. Através da Figura 3 é possível
observar o consumo de um única UCP (Unidade Central de Processamento) para realizar a
busca e ordenação de maneira sequencial, ou seja, sem fazer o uso do paralelismo.

Figura 2: resultado de tempo gasto pela UCP para ordenação de vetores via MergeSort de
maneira sequencial.
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 4

Figura 3: resultado de uso da UCP para ordenação de vetores via MergeSort de maneira se-
quencial.

3 Programa: MergeSort com o recurso de paralelismo do


Pthread
O algoritmo descrito na Seção 2 foi modificado para fazer o uso de mais de um núcleo
da UCP e pode ser observado no Apêndice 4.1. Para explorar o paralelismo foi utilizado a API
Pthread. Para que fosse possível observar o uso real da UCP e de seus vários núcleos, foi feito:

• O algoritmo executou 3 vezes, cada vez com um tamanho de entrada (foi utilizado um for
para isso):

– 10 × 10.000
– 100 × 10.000
– 1000 × 10.000

• Para cada entrada definida no item anterior o método recursivo do mergeSort foi dividido
em 2 threads principais.

Dessa forma, foi possível observar no monitor de sistema o uso da UCP em tempo de
execução como demonstrado na Figura 4
Após a execução de vários experimentos, não houve melhora significativa do uso do pa-
ralelismo em relação ao uso tradicional do algoritmo de Merge Sort.
Ao aumentar o tamanho do vetor, foi observado que ambos os algoritmos passaram a
demorar mais para processar, contudo o Algoritmo sequencial obtinha melhores resultados.
Para um vetor muito grande, a diferença caia consideravelmente. A sensação que dá, é que
se aumentar mais ainda, o algoritmo paralelo passará a ser mais vantajoso, porém, ao fazer
essa operação o computador apresentava erro de “Falha de segmentação (imagem do núcleo
gravada)”.
Uma melhor estruturação do Algoritmo para maximizar o uso da memória e libera-la
quando não mais em uso, pode minimizar este problema.
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 5

Figura 4: resultado de uso da UCP para ordenação de vetores via MergeSort de maneira paralela
com a API Pthread.

4 Apêndice
4.1 mergeSortComPthread.c
# i n c l u d e < p t h r e a d . h>
# i n c l u d e < s t d i o . h>
# i n c l u d e < s t d l i b . h>

5 s t r u c t merge_data {
int i ;
int j ;
int ∗ data ;
};
10
/∗
∗ metodo n e c e s s á r i o p a r a o p t h r e a d
∗/
void ∗ mergesort ( void ∗ data ) {
15 s t r u c t merge_data ∗ value = ( s t r u c t merge_data ∗) data ;
s t r u c t merge_data v e t o r D i r e i t o ;
s t r u c t merge_data vetorEsquerdo ;
i n t i , j , k , metade_vetor ;

20 pthread_t thread_esquerda ;
pthread_t thread_direita ;

m e t a d e _ v e t o r = ( i n t ) ( v a l u e −> i + v a l u e −> j ) / 2 ;

25 /∗
∗ c r i a o v e t o r da e s q u e r d a
∗/
i f ( ( ( v a l u e −> j − v a l u e −> i ) ) >= 1 ) {
vetorEsquerdo . data = ( i n t ∗) malloc ( s i z e o f ( i n t ) ∗ (
m e t a d e _ v e t o r − v a l u e −> i + 1 ) ) ;
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 6

30 vetorEsquerdo . i = 0;
v e t o r E s q u e r d o . j = ( m e t a d e _ v e t o r − v a l u e −> i ) ;
f o r ( i = v a l u e −> i , j = 0 ; i <= m e t a d e _ v e t o r ; i ++ , j ++) {
v e t o r E s q u e r d o . d a t a [ j ] = v a l u e −> d a t a [ i ] ;
}
35
v e t o r D i r e i t o . d a t a = ( i n t ∗ ) m a l l o c ( s i z e o f ( i n t ) ∗ ( v a l u e −> j
− metade_vetor ) ) ;
vetorDireito . i = 0;
v e t o r D i r e i t o . j = ( v a l u e −> j − m e t a d e _ v e t o r − 1 ) ;
/∗
40 ∗ C r i a o v e t o r da d i r e i t a
∗/
f o r ( i = m e t a d e _ v e t o r + 1 , j = 0 ; i <= v a l u e −> j ; i ++ , j ++)
{
v e t o r D i r e i t o . d a t a [ j ] = v a l u e −> d a t a [ i ] ;
}
45
/∗
∗ C r i a a s d u a s t h r e a d s p r i n c i p a i s p a r a o r d e n a r de m a n e i r a
paralela
∗/
p t h r e a d _ c r e a t e (& t h r e a d _ e s q u e r d a , NULL, m e r g e s o r t , &
vetorEsquerdo ) ;
50 p t h r e a d _ c r e a t e (& t h r e a d _ d i r e i t a , NULL, m e r g e s o r t , &
vetorDireito ) ;
} else {
v e t o r E s q u e r d o . d a t a = v a l u e −> d a t a ;
v e t o r E s q u e r d o . i = v a l u e −> i ;
v e t o r E s q u e r d o . j = v a l u e −> j ;
55 v e t o r D i r e i t o . d a t a = v a l u e −> d a t a ;
v e t o r D i r e i t o . i = v a l u e −> i ;
v e t o r D i r e i t o . j = v a l u e −> j ;
}

60 /∗
∗ R e p o n s á v e l p e l a j u n ç ã o d o s v e t o r e s da E s q u e r d a com o da D i r e i t a .
∗/
p t h r e a d _ j o i n ( t h r e a d _ e s q u e r d a , NULL) ;
p t h r e a d _ j o i n ( t h r e a d _ d i r e i t a , NULL) ;
65

i = j = 0;
f o r ( k = v a l u e −> i ; k <= v a l u e −> j
&& ( i <= v e t o r D i r e i t o . j )
&& ( j <= v e t o r E s q u e r d o . j ) ; k ++) {
70 /∗
∗ Se o v e t o r da D i r e i t a f o r menor que o da E s q u e r d a
∗ o r d e n a o v e t o r da D i r e i t a
∗ c a s o c o n t r á r i o da E s q u e r d a
∗/
75 i f ( vetorDireito . data [ i ] < vetorEsquerdo . data [ j ]) {
v a l u e −> d a t a [ k ] = v e t o r D i r e i t o . d a t a [ i + + ] ;
} else {
v a l u e −> d a t a [ k ] = v e t o r E s q u e r d o . d a t a [ j + + ] ;
}
80 }
/∗
∗ 1 − A d i c i o n a o que s o b r o u no v e t o r
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 7

∗ 2 − Parcialmente ordenado
∗/
85 w h i l e ( ( i <= v e t o r D i r e i t o . j ) ) {
v a l u e −> d a t a [ k ++] = v e t o r D i r e i t o . d a t a [ i + + ] ;
}

w h i l e ( ( j <= v e t o r E s q u e r d o . j ) ) {
90 v a l u e −> d a t a [ k ++] = v e t o r E s q u e r d o . d a t a [ j + + ] ;
}

p t h r e a d _ e x i t (NULL) ;
}
95
i n t main ( i n t a r g c , c h a r ∗ a r g v [ ] ) {
c l o c k _ t t e m p o I n i c i a l , t e m p o F i n a l ; / / V a r i a v e l p a r a c a p t u r a r o tempo
pthread_t thread ;
int i ;
100 i n t rc ;
i n t tamanhoVetor = 100000;
s t r u c t merge_data s t r u c t _ d a t a ;

i n t d at a [ tamanhoVetor ] ;
105

f o r ( i = 0 ; i < t a m a n h o V e t o r ; i ++) {
data [ i ] = rand ( ) ;
}

110 struct_data . data = data ;


s t r u c t _ d a t a . i = 0;
s t r u c t _ d a t a . j = ( tamanhoVetor − 1) ;
/∗
∗ Obtem o tempo i n i c i a l da e x e c u ç ã o
115 ∗/
tempoInicial = clock () ;
r c = p t h r e a d _ c r e a t e (& t h r e a d , NULL, m e r g e s o r t , ( v o i d ∗ ) &s t r u c t _ d a t a
);
i f ( rc ) {
p r i n t f ( "ERROR; return code from pthread_create() is %d\n" ,
rc ) ;
120 e x i t ( −1 ) ;
}

p t h r e a d _ j o i n ( t h r e a d , NULL) ;

125 tempoFinal = clock ( ) ;


/∗
∗ Imprime o tempo g a s t o na e x e c u ç ã o
∗/
p r i n t f ( "Tempo gasto: %lf segundos \n" , ( d o u b l e ) ( t e m p o F i n a l −
t e m p o I n i c i a l ) / CLOCKS_PER_SEC ) ;
130 // p r i n t f ( " \ n \ nVETOR ORDENADO\ n " ) ;
// f o r ( i =0 ; i < t a m a n h o V e t o r ; i ++) {
// p r i n t f ("% d " , d a t a [ i ] ) ;
// }
// printf ("\ n \ n ") ;
135 /∗
∗ l i b e r a a memória a r m a z e n a d a p a r a o s d a d o s .
∗/
Relatório técnico: Programação Paralela e Distribuída (PPD) - Lista de Exercício 2 8

free ( data ) ;
p t h r e a d _ e x i t (NULL) ;
140 / ∗ L a s t t h i n g t h a t main ( ) s h o u l d do ∗ /
}

Referências