You are on page 1of 19

Wayan Sriyasa/G651080154

Departemen Ilmu Komputer, FMIPA, IPB

Algoritma Parallel Perkalian Matrix:


CANNON vs FOX

Latar Belakang
Perkalian dua matrix yang masing-masing berukuran n x n dari matrix persegi A dan
B untuk menghasilkan matrix C (C = AxB) secara parallel dengan menggunakan prosesor
sebanyak m, dimana m ≤ n pada dasarnya mirip dengan perkalian matrix dengan
metode konvensional (algoritma sekuensial).
Dengan mengasumsikan bahwa:
1. n sel matrix adalah hasil pangkat 2.
2. Jumlah processor yang digunakan adalah m = n^3 sehingga n > m
3. processor di disusun dalam array tiga dimensi. Processor Pi,j,k masing-masing
dengan index (i,j,k)
4. digunakan 3 dimensi array C[1..n,1..n,1..n] dalam shared memory sebagai
tempat kerja
5. Hasil matrix akan disimpan dalam lokasi C[i,j,n], dimana 1≤ i,j ≤ n
Algoritma sekuensial-nya adalah
Algoritma 1
1. procedure MAT_MULT (A, B, C)
2. begin
3. for i := 0 to n - 1 do
4. for j := 0 to n - 1 do
5. begin
6. C[i, j] := 0;
7. for k := 0 to n - 1 do
8. C[i, j] := C[i, j] + A[i, k] x B[k, j];
9. endfor;
10. end MAT_MULT

Sekilas dapat diketahui bahwa waktu terburuk yang dibutuhkan oleh algoritma diatas
adalah sebanyak n3 atau θ(n3).
Proses parallelisasi algoritma diatas dapat dilakukan dengan menggunakan
pendekatan block matrix operations, dimana matrix asal yang relatif berukuran besar
dipecah menjadi blok kecil, misal matrix dengan ukuran nxn dapat dibagi menjadi
beberapa matrix kecil dengan ukuran qxq dimana Ai,j (0 ≤ i, j < q)). Sedemikian sehingga
setiap block akan berukuran (n/q) x (n/q). Dengan demikian algoritma diatas dapat
dimodifikasi menjadi:
Algoritma 2

1. procedure BLOCK_MAT_MULT (A, B, C)


2. begin
3. for i := 0 to q - 1 do
4. for j := 0 to q - 1 do
5. begin
6. Initialize all elements of Ci,j to zero;
7. for k := 0 to q - 1 do
8. Ci,j := Ci,j + Ai,k x Bk,j;
9. endfor;
10. end BLOCK_MAT_MULT

Pada algoritma 2, terlihat pada baris 8 dilakukan operasi penjumlahan dan perkalian
sekaligus. Berbeda dengan algoritma 1, pada algoritma 2 terjadi perkalian matrix
sebanyak q3 yang melibatkan matrix (n/q) x (n/q) dan memerlukan sebanyak (n/q)3
1
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

penjumlahan serta perkalian. Proses ini dapat kita bagi kedalam p prosesor secara
parallel dengan memilih q  p dan melakukan komputasi blok kecil Ci,j ke setiap
ptosesor.

Teknik Partisi Data - Checkerboard


Ada tiga teknik dekomposisi data yang dapat digunakan dalam implementasi
perkalian matrix ini, antara lain: dekomposisi berdasarkan baris, kolom atau dengan
menggunakan teknik blok checkerboard. Pada tulisan ini, teknik dekomposisi data yang
akan digunakan adalah teknik checkerboard.
Teknik checkerboard, matrix dibagi menjadi blok 2 dimensi yang disesuaikan
dengan grid-nya. Dengan mengasumsikan p merupakan sejumlah prosesor yang
membentuk grid dengan sebanyak r baris dan c kolom. Setiap proses bertanggung
jawab atas komputasi blok matrix yang setidaknya mengandung sebanyak [m/r] baris
dan [n/c] kolom (ukuran matrix = m x n).
Dengan mengasumsikan matrix berukuran nxn A dan B dipecah sebanyak p blok
   n 
Ai,j dan Bi,j dengan 0  k  p dengan ukuran tiap bloknya  n  x
 
 . Blok ini
 p  p 
dipetakan kedalam jaring proses berukuran p x p , tiap proses diberi nama mulai dari
P0,0 hingga P p 1 , p 1
. Proses Pi,j biasanya menyimpan nilai Ai,j dan Bi,j menghitung hasil
perkalian blok Ci,j. Menghitung sub-matrix Ci,j membutuhkan sub-matrix Ai,k dan Bk,j
( 0  i , j  p ). Untuk memperoleh nilai setiap blok, dilakukan all-to-all broadcast blok
matrix A disetiap baris dan all-to-all broadcast blok matrix B disetiap kolom. Setelah nilai
Pi,j diperoleh Ai ,0 , Ai ,1,..., Ai , p 1 dan B 0, j , B1, j ,..., B p1 kemudian dilakukan perkalian dan
penjumlahan sub-matrix ini (algoritma 2, baris 7 & 8).

Algoritma Cannon
Algoritma cannon merupakan salah satu algoritma yang dapat digunakan untuk
melakukan perkalian matrix dengan pemakaian memori yang efisien. Berikut merupakan
detail dari algoritma Cannon:
1. inisialisasi prosesor Pi,j dengan elemen ai,j dan bi,j (0≤ i < n; 0 ≤ j < n).
2. elemen dipindahkan dari posisi awal sebagai berikut: matrix A beris ke-i diputar
satu putaran ke kiri dan matrix B kolom ke-j diputar satu putaran keatas sehingga
akan dihasilkan matrix baru dengan elemen ai,j+i dan bi+j,j .
j

i
A
Pi,j Gambar 1. perputaran elemen matrix A
dan B.

3. setiap prosesor Pi,j melakukan perkalian masing-masing elemennya.


4. setelah proses 3 selesai, kemudian putaran matrix kembali dilakukan, dimana
elemen baris ke-i matrix A akan diputar satu putaran ke kiri dan elemen kolom ke-1
matrix B akan diputar satu putaran ke atas.
5. kemudian setiap prosesor Pi,j kembali melakukan perkalian elemen yang baru hasil
putaran pada langkah 4 dan hasilnya disimpan pada variabel jumlah total
perkalian ini.

2
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

6. langkah 4 dan 5 dilakukan secara berulang sampai dengan seluruh elemen baris
dan kolom diputar (n-1 putaran baris dan kolom).

Berikut desain foster untuk algoritma tersebut:

 Partitioning & Agglomeration, algoritma ini menggunakan teknik checkerboard


untuk melakukan partisi data kedalam blok matrix yang lebih kecil. Misalkan matrix
A dan B dibagi menjadi masing-masing p blok matrix. Masing-masing proses dari
P0,0 hingga P p 1, p 1 akan memiliki blok Ai,j dan Bi,j. Agglomerasi dilakukan dengan
orientasi baris, dimana setiap prosesor akan melakukan komputasi terhadap
seluruh elemen C, dan ini memerlukan akses terhadap seluruh elemen B (gambar
2a). Sesuai dengan teknik checkerboard diatas, setiap prosesor akan melakukan
   n 
komputasi blok matrix C dengan ukuran  n  x
 
 , untuk melakukan
 p  p 
komputasi elemen ini prosesor memerlukan referensi dari elemen matrix B sebanyak
 n   n 
  baris dan   kolom (gambar 2b.).
 p   p 

x =

A B C

2a

x =

A B C

2b

Gambar 1. Perbandingan banyaknya elemen A dan B yang perlu dihitung


oleh setiap prosesor.
a) Perkalian berdasarkan baris, setiap prosesor akan
menghitung sebanyak n/p baris dari C dan perlu untuk
mengakses sebanyak n/p baris A dan seluruh elemen B.
b) Pada algoritma cannon, setiap prosesor akan melakukan
   
komputasi sebanyak  n  x n  blok matrix C. Proses
 p   p 
 
ini akan mengakses sebanyak  n  baris A dan .B
 p 

3
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

3
Setiap blok/proses akan melakukan komputasi sebanyak  2n  , dimana
 p 
 
setiap blok akan mengakses sebanyak 2n n  elemen. Rasio antara komputasi
 p 
3
2n
p n
dan komunikasi yang terjadi adalah 2
 .
2n p
p

 Communication, diperlukan untuk melakukan perputaran elemen matrix A dan B.


Setiap proses pada baris ke-i matrix A akan memindahkan isi blok tersebut ke kiri
sebanyak 1 putaran, demikian juga pada kolom matrix B akan memindahkan isi
blok-nya sebanyak satu putaran ke atas (ilustrasi gambar 3).

Gambar 3. Proses komunikasi yang terjadi pada algoritma Cannon


dengan mengunakan sebanyak 16 prosesor/blok.

Pada ilustrasi diatas terlihat proses komunikasi terjadi ketika algoritma


melakukan inisialisasi elemen matrix dengan melakukan pergeseran elemen baris
matrix A kekiri dan kolom matrix B keatas. Dan setiap blok melakukan perkalian
elemen-ya, dan kembali diputar dengan arah yang sama sampai dengan baris ke
n-1 dan kolom ke n-1 juga.

4
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Proses putaran elemen ini melibatkan sebanyak Ai ,( j  i ) mod p


dan
B(i  j ) mod p, j
. Berikut cuplikan kode program untuk melakukan putaran elemen
matrix sekaligus menggantikan nilai blok dengan elemen yang baru tersebut:

/*********************************************************/
/*putar blok & isikan nilai perhitungan*/
MPI_Cart_shift(GRID_COMM,1,-1,&source,&dest);
MPI_Sendrecv_replace(TA,S2,MPI_INT,dest,0,source,
0,GRID_COMM,&status);
MPI_Cart_shift(GRID_COMM,0,-1,&source,&dest);
MPI_Sendrecv_replace(TB,S2,MPI_INT,dest,0,source,
0,GRID_COMM,&status);
/*********************************************************/

Cuplikan kode berikut merupakan topologi virtual yang digunakan pada algoritma
cannon ini:

/*********************************************************/
/*untuk buat topologi*/
M=(int)sqrt(nproc);
S=N/M; /*dimensi blok*/
S2=S*S; /*dimensi blok*/
dims[0]=dims[1]=M; /*dimensi topologi*/
periods[0]=periods[1]=1;
//membuat comm baru
MPI_Cart_create(MPI_COMM_WORLD,2,dims,periods,0,&GRID_COMM);
MPI_Comm_rank(GRID_COMM,&grid_rank);
MPI_Cart_coords(GRID_COMM,grid_rank,2,coords);
myid=grid_rank;
source=coords[0];
dest=coords[1];
/*********************************************************/
Detail lengkap kode program dapat dilihat pada lampiran 1.

Algoritma Fox
Mirip dengan algoritma Cannon, algoritma Fox juga melakukan rotasi elemen,
tetapi rotasi elemen yang terjadi melibatkan broadcast elemen baris matrix A dan
perputaran kolom matrix B pada setiap tahap komputasinya. Berikut merupakan langkah
yang dilakukan pada algoritma Fox:
1. dilakukan perkalian elemen matrix ai,j x bi,j, ci,j  ai,j x bi,j
2. tahap berikutnya (tahap ke k, 1 ≤ k < n) dilakukan: ci,j  ci,j + ai,k x bk,j
dimana k = (i+k)mod n, n = merupakan ukuran matrix tersebut.
Pada tahap 1, ci,j dihitung sebagai hasil perkalian dari ai,j dan bi,j, dan pada tahap ke-k,
ci,j dihitung sebagai hasil perkalian antara ai,k dengan bk,j.
Algoritma sekuensial diatas dapat diparallelkan kedalam sejumlah prosesor (p<n).
 n
Ukuran setiap blok matrix adalah q x q dimana q  p dan n  . Pada setiap langkah
q
ke-k>0, proses pi,j (0 ≤ i, j ≤ q) akan menghitung sub-blok ci,j sebagai hasil perkalian dari
sub-blok ai,k yang di-broadcast oleh proses pi,k (pada baris yang sama) dan bi,k dari pi,j
proses dari atas kebawah dari pk ,j.

5
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Berikut algoritma parallel Fox:

set C = 0
for (stage = 0 ∶ p − 1) do
o Tiap baris prosesor i, mem-broadcast sub-blok Ai ,( j i ) mod p
ke prosesor lain pada
baris yang sama, setiap prosesor menyimpan subblok broadcast dalam sebuah
array T
o Kalikan sub-matriks temporer T pada tiap prosesor dengan sub-blok B sekarang dan
tambahkan hasilnya ke C
o Setiap prosesor mengirimkan sub-blok B sekarang ke prosesor di atasnya dan
menerima sub-blok dari prosesor di bawahnya dan dijadikan sebagai sub-blok
sekarang yang baru. Wrap around dari atas ke bawah.
end

Berikut desain Foster untuk algoritma tersebut:


 Partitioning & Agglomeration, algoritma ini menggunakan teknik checkerboard
untuk melakukan partisi data kedalam blok matrix yang lebih kecil. Misalkan matrix
A dan B dibagi menjadi masing-masing p blok matrix. Masing-masing proses dari
P0,0 hingga P p 1, p 1 akan memiliki blok Ai,j dan Bi,j. Agglomerasi dilakukan dengan
orientasi baris, dimana setiap prosesor akan melakukan komputasi terhadap
seluruh elemen C, dan ini memerlukan akses terhadap seluruh elemen B (gambar
2a). Sesuai dengan teknik checkerboard diatas, setiap prosesor akan melakukan
   n 
komputasi blok matrix C dengan ukuran  n  x
 
 , untuk melakukan
 p  p 
komputasi elemen ini prosesor memerlukan referensi dari elemen matrix B sebanyak
 n   n 
  baris dan   kolom. Gambar 4, merupakan model pembagian blok
 p   p 
matrix yang akan ditangani oleh setiap prosesor.

Gambar 4. Pembagian matrix kedalam blok.

 Communication, proses komunikasi terjadi sesuai dengan ilustrasi pada gambar 5,


komunikasi yang terjadi adalah komunikasi kolektif. Algoritma Fox memiliki 3
langkah proses yang dikenal dengan broadcast, multiply dan roll yang terjadi
disetiap iterasinya. Komunikasi kolektif yang terjadi adalah ketika terjadi broadcast
sepanjang baris dan roll/pergeseran pada kolom. Rowbroadcast adalah
6
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

broadcast pada sub-grup khusus dari prosesor. Roll dilakukan sebagai varian dari
operasi MPI_Sendrecv dengan kondisi batas melingkar (wrapped). Berikut
merupakan ilustrasi proses komunikasi yang terjadi pada algoritma Fox:

5a.

Gambar 5. langlah-langkah algoritma Fox:


5a. langkah ke-1, row broadcast, inisialisasi,
perkalian elemen matrix A dan B menghasilkan
matrix C

5b. langkah ke-2, n=1, dilakukan perputaran elemen


matrix b ke atas dan diikuti dengan broadcast
elemen matrix A ke arah kanan.

5c. langkah berikutnya, mengalikan sub-blok dan


menjumlahkannya kedalam matrix C.

7
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

5c.

Gambar 5. Proses komunikasi yang terjadi pada algoritma Fox.

Implementasi dan hasil Running


Implementasi kedua algoritma ini dilakukan dengan menggunakan bahasa C dan
modul MPI dari Microsoft ClusterPack dengan IDE Visual Studio Express. Detail lengkap
kode program kami sertakan pada lampiran. Pada bagian ini akan ditampilkan fungsi
utama-nya saja dari kode program yang telah dibuat.

Algoritma Cannon
Input dan output untuk program ini adalah berupa file text yang berisi data. File
yang dibaca terdiri dari file matrix A dan file matrix B (contoh file terlampir pada
softcopy). Berikut adalah hasil run dari program yang dibuat:

Gambar 6. Contoh tampilan layar hasil eksekusi program Cannon.

Output tampilan layar dari program ini adalah berupa informasi prosesor yang bekerja
dan waktu yang butuhkan untuk melakukan komputasi. Sebagai input digunakan matrix
berukuran 100 x 100 dan disimpan didalam file text. Hasil tidak ditampilkan pada console.

8
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Algoritma Fox
Berikut merupakan contoh tampilan layar dari program Fox yang dibut.

Gambar 7. Contoh tampilan layar hasil eksekusi program Fox.

Hubungan Ukuran Matrix v s Waktu


Komputasi
waktu eksekusi
6
5
4
ms

3
2
1
0
0 20 40 60 80
ordo matrix

Gambar 8. Grafik hubungan antara waktu eksekusi dengan ukuran matrix.

9
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Hubungan Waktu Eksekusi vs Jumlah Prosesor

jumlah prosesor
0.7
0.6
0.5
ms 0.4
0.3
0.2
0.1
0
0 5 10 15 20 25 30
#prosesor

Gambar 9. Hubungan jumlah prosesor dengan waktu eksekusi

Performa Dan Skalabilitas Algoritma

Beberapa parameter yang dapat digunakan untuk mengukur kinerja sebuah


algoritma antara lain speed up, efisiensi dan isoefisiensi. Berikut merupakan analisa
paremeter tersebut untuk kedua algoritma diatas.

Algoritma Cannon
Seperti terlihat pada gambar 3, terjadi perputaran baris dan kolom dimana, jarak
maksimum yang ditempuh oleh satu blok shift adalah p  1 . Operasi untuk dua putaran
2
tersebut memerlukan waktu total sebanyak 2 t s  t w n  . Setiap langkah dari p proses
 p 
2
memerlukan waktu sebesar t s  t w n . Sehingga total waktu komunikasi yang diperlukan
p
2
adalah 2 t s  t w n  p.
 p 
Sedangkan untuk proses komputasinya sendiri memerlukan waktu sebagai berikut,
   n 
setiap proses akan melakukan sebanyak p perkalian dari sub-blok  n  x
 
.
 p  p 
Dengan mengasumsikan bahwa setiap proses perkalian dan penjumlahan menggunakan
satu satuan waktu, maka total waktu yang diperlukan untuk setiap proses untuk
3
melakukan komputasi adalah sebesar n . Dengan demikian total waktu parallel yang
p
n3 n2
dibutuhkan oleh algoritma cannon adalah: Tp   2 p t s  2t w .
p p

10
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

o Speed up untuk algoritma ini menjadi:

Ts n3
SN   3
Tp n n2
 2 pt s  2t w
p p
o Efisiensinya adalah
Ts n3
E ff  
pT p  n3 n 2 
p   2 pt s  2t w
 p p 

o Isoefisiensi, dengan memperhatikan waktu proses dari algoritma ini yaitu
 n3 n 2 
p  2 p t s  2t w dan cost optimum untuk algoritma parallel ini adalah
 p p 

3 3
p=O(n2). Sehingga fungsi isoefisiensi untuk ts dan tw adalah 2 p 2 t s dan 8t w  p
3 2
,
dengan demikian isoefisiensi sebagai akibat adanya overhead komunikasi adalah
3
 p 2  Dengan melihat nilai pangkat dari fungsi isoefisiensi tersebut diketahui
 
bahwa untuk mendapatkan efisiensi yang sama dengan ketika jumlah prosesor p
x3
2
maka ukuran masalah juga harus bertambah sebesar
p . Dengan kata lain,
3
2
p
apabila misalnya jumlah masalah semula adalah n3 dengan prosesor semula
adalah 4 (22) kemudian ditingkatkan menjadi 16(24) maka jumlah masalah harus
bertambah menjadi (2n)3.

Algoritma Fox
Berikut merupakan analisa kinerja algoritm Fox:
ada tiga komponen waktu yang harus dihitung untuk menentukan waktu parallel yang
diperlukan oleh algoritma Fox ini, antara lain:
waktu untuk broadcast (tbroad):
  2
t broad  log p  t s  t w n  n   log p  t s  n t w 
p p  p 

waktu untuk mengalikan matrix (tmul):


3
  3
t mull   n   n
 p p p
waktu untuk melakukan rolling (troll):
2
t roll  t s  n  n tw  ts  n tw
p p p
sehingga total waktu parallel untuk satu iterasi adalah Tp = tbroad + tmul + troll
 3  
T p  log p  t s  n t w   n
2 2
  t s  n t
p  p 
   p p  

3 2
Tp  n  log 4 p  t s  n t w 
p p  p 

11
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Dengan demikian total waktu yang dibutuhkan untuk seluruh proses yaitu sebanyak p
iterasi adalah
Tp  Tp  p
 3 2 
Tp  p  n  log 4 p  t s  n t w 
 p 
 p p
3 2
 n  p log 4 p  t s  n t w 
p  p 
3 2
 n  log 4 pt s  n log 4 pt w
p p
o Speed up, dengan demikian speed up algoritma ini dapat ditentukan sebagai
berikut:
Ts n3
SN  
Tp n3  log 4 p t s  n
2
log 4 pt w
p p
o Efisiensinya adalah
Ts n3
E ff  
pT p  3 2 
p n  log 4 pt s  n log 4 pt w 
p p
 
o Isoefisiensi, dengan memperhatikan waktu proses dari algoritma ini yaitu
 3 2 
p n  log 4 p ts  n log 4 pt w  dan cost optimum untuk algoritma parallel ini
p p
 
adalah p=O(n2). Sehingga fungsi isoefisiensi untuk ts dan tw adalah
3 1 1 1
p 2
log(4 p) 2 t s dan n 2 p 2
log( 4 p) 2 t w , dengan demikian isoefisiensi sebagai akibat
adanya overhead komunikasi logaritmik dari fungsi broadcast adalah
3 1
 p 2
log 3 (4 p ) 2  
 
Perbandingan
Dengan melihat nilai speed up, effisiensi dan isoefisiensi diatas, dapat disimpulkan
bahwa algoritma cannon memiliki kinerja yang lebih baik daripada algoritma Fox.
Dimana algoritma cannon memiliki skalabilitas yang lebih baik daripada algoritma Fox
(koefisien isoefisiensi Fox > isoefisiensi Cannon).
Sebuah ekperimen yang dilakukan oleh Alqadi et.al (2008) menunjukkan bawah
algoritma Cannon memang memiliki kinerja yang lebih baik daripada algoritm Fox
(cuplikan tabel berikut)

12
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Eksperimen tersebut menunjukkan bahwa faktor Speed up (SP) dan efisiensi (E) yang
dihasilkan oleh algoritma Cannon lebih baik dari pada Fox. Ulasan lebih lengkap
mengenai eksperimen ini dapat merujuk pada referensi terlampir.

Kesimpulan
Algoritma Cannon dan Fox merupakan algoritma perkalian matrix yang dapat
diimplementasikan dengan menggunakan teknik virtual topologi. Kedua algoritma
menggunakan beberapa tahapan untuk menghitung hasil perkalian dua buah matrix
persegi. Pada algoritma Cannon, pendekatan yang digunakan dengan orientasi
putaran blok matrix berdasarkan baris dan kolom, sedangkan algoritma Fox
menggunakan pendekatan broadcast baris matrix A dan putaran keatas kolom matrix B.
Algoritma ini memiliki kesamaan yaitu sangat efisien dalam pemakaian
memori,tetapi jika dibandingkan dengan lebih detail algoritma Cannon memiliki efisiensi
dan skalabilitas yang lebih daripada algoritma Fox.

Referensi
Akpan, O.H. ____. Efficient Parallel Implementation of The Fox Algorithm. Computer
Science Dept. Bowie State Univ.
Alqadi, Z.A.A; Aqel,M; Emary, I.M.M.E. 2008. Performance Analysis and Evaluation of
Parallel Matrix Multiplication Algorithms. World Applied Sciences Journal 5 (2):
211-214, 2008. IDOSI Publications
Grama, A; Gupta, A; Karypis, George; dan Kumar, V. 2003. Introduction to Parallel
Computing, Second Edition – Chapter 8. Dense Matrix Algorithms. Addison
Wesley. USA
Quinn, M.J. 2004. Parallel Programming in C with MPI and OpenMP. McGrawHill. USA.
Wilkinson, B; Allen, M. 2005. Parallel Programming: Techniques and Applications Using
Networked Workstations and Parallel Computers, 2nd edition. Prentice Hall.
USA.

13
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

Lampiran 1. Source Code


Algoritma Cannon
#include <mpi.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#define N 100 /* 512*/

void Print_Matrix(int x, int y, int myid,int S, int *M);

int A[N][N],B[N][N],C[N][N];
int main(int argc, char **argv){
int myid, S, M, nproc,source,dest;
int i,j,k,m,l,repeat,temp,S2;
int namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Status status;
double t1, t2,t3,t4;

int *T,*TA,*TB,*t,*TC;
MPI_Comm GRID_COMM;
int ndims,dims[2];
int periods[2],coords[2],grid_rank;

MPI_Init(&argc, &argv); /* inisialisasi MPI */


MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Comm_size(MPI_COMM_WORLD,&nproc); /* #procesor */
MPI_Get_processor_name(processor_name,&namelen);

printf("Process %d of %d on %s\n",myid, nproc, processor_name);

if(myid==0) {
/* baca data dari files: "A_file", "B_file"*/
if (readmat("A_file.txt", (int *) A,N) < 0)
exit( 1 + printf("file problem\n") );
if (readmat("B_file.txt", (int *) B, N) < 0)
exit( 1 + printf("file problem\n") );
/*catat waktu*/
t1=MPI_Wtime();
}
/*untuk buat topologi*/
M=(int)sqrt(nproc);
S=N/M; /*dimensi blok*/
S2=S*S; /*dimensi blok*/
dims[0]=dims[1]=M; /*dimensi topologi*/
periods[0]=periods[1]=1;
MPI_Cart_create(MPI_COMM_WORLD,2,dims,periods,0,&GRID_COMM);

MPI_Comm_rank(GRID_COMM,&grid_rank);
MPI_Cart_coords(GRID_COMM,grid_rank,2,coords);
myid=grid_rank;
source=coords[0];
dest=coords[1];

/*siapin untuk wadah matrix input dan output*/


TA=(int *)malloc(sizeof(MPI_INT)*S2);
TB=(int *)malloc(sizeof(MPI_INT)*S2);
TC=(int *)malloc(sizeof(MPI_INT)*S2);

for(i=0; i<S2; i++)


TC[i]=0;

/*mulai proses canon*/


if(myid==0)
{
T=(int *)malloc(sizeof(MPI_INT)*S2);
t3=MPI_Wtime(); /*timing*/
for(k=0; k<nproc; k++){
MPI_Cart_coords(GRID_COMM,k,2,coords);
if(k==0){
t=TA;
for(i=k; i<k+S; i++){
temp=(k*S)%N;
for(j=temp; j<temp+S; j++){
*t=A[i][j];
t++;
}

14
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

}
}
else{
t=T;
for(i=coords[0]*S; i<(coords[0]+1)*S; i++)
for(j=coords[1]*S; j<(coords[1]+1)*S; j++){
*t=A[i][j];
t++;
}
MPI_Send(T,S2,MPI_INT,k,0,GRID_COMM);
}
}

for(k=0; k<nproc; k++){


MPI_Cart_coords(GRID_COMM,k,2,coords);
if(k==0){
t=TB;
for(i=k; i<k+S; i++){
temp=(k*S)%N;
for(j=temp; j<temp+S; j++){
*t=B[i][j];
t++;
}
}
}
else{
t=T;
for(i=coords[0]*S; i<(coords[0]+1)*S; i++)
for(j=coords[1]*S; j<(coords[1]+1)*S; j++){
*t=B[i][j];
t++;
}
MPI_Send(T,S2,MPI_INT,k,1,GRID_COMM);
}
}

coords[0]=source;
coords[1]=dest;
t4= MPI_Wtime();

/*perkalian matrix*/
for(repeat=0; repeat<N/S; repeat++){
for(i=0; i<S; i++){
for(j=0; j<S; j++){
for(k=0; k<S; k++){
TC[i*S+j]+=TA[i*S+k]*TB[j+k*S];
}
}
}
/*putar blok & isikan nilai perhitungan*/
MPI_Cart_shift(GRID_COMM,1,-1,&source,&dest);
MPI_Sendrecv_replace(TA,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);

MPI_Cart_shift(GRID_COMM,0,-1,&source,&dest);
MPI_Sendrecv_replace(TB,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);
}

for(i=0; i<S; i++)


for(j=0; j<S; j++){
C[i][j]=TC[i*S+j];
}

for(i=1; i<nproc; i++){


l=0;
m=0;

MPI_Recv(T,S2,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,GRID_COMM,&status);
MPI_Cart_coords(GRID_COMM,status.MPI_TAG,2,coords);

for(j=coords[0]*S; j<(coords[0]+1)*S; j++){


for(k=coords[1]*S; k<(coords[1]+1)*S; k++){
C[j][k]=T[l*S+m];
m++;
}
l++;
m=0;
}
}

15
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

t2= MPI_Wtime();
printf("Total Time: %lf msecs \n",(t2 - t1) / 0.001);
//printf("Transmit Time: %lf msecs \n",(t4 - t3) / 0.001);
writemat("C_file_par", (int *) C, N);

free(T);
free(TA);
free(TB);
free(TC);
}
else
{
MPI_Recv(TA,S2,MPI_INT,0,0,GRID_COMM,&status);
MPI_Recv(TB,S2,MPI_INT,0,1,GRID_COMM,&status);

MPI_Cart_shift(GRID_COMM,1,-coords[0],&source,&dest);
MPI_Sendrecv_replace(TA,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);

MPI_Cart_shift(GRID_COMM,0,-coords[1],&source,&dest);
MPI_Sendrecv_replace(TB,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);
for(repeat=0; repeat<N/S; repeat++){
for(i=0; i<S; i++){
for(j=0; j<S; j++){
for(k=0; k<S; k++){
TC[i*S+j]+=TA[i*S+k]*TB[j+k*S];
}
}
}

MPI_Cart_shift(GRID_COMM,1,-1,&source,&dest);
MPI_Sendrecv_replace(TA,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);

MPI_Cart_shift(GRID_COMM,0,-1,&source,&dest);
MPI_Sendrecv_replace(TB,S2,MPI_INT,dest,0,source,0,GRID_COMM,&status);
}

MPI_Send(TC,S2,MPI_INT,0,myid,GRID_COMM);
free(TA);
free(TB);
free(TC);
}
MPI_Finalize();
return(0);
}
/*Fungsi untuk baca input dan tulis output kedalam file*/
#define _mat(i,j) (mat[(i)*n + (j)])
readmat(char *fname, int *mat, int n){
FILE *fp;
int i, j;
if ((fp = fopen(fname, "r")) == NULL)
return (-1);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if (fscanf(fp, "%d", &_mat(i,j)) == EOF){
fclose(fp);
return (-1);
};
fclose(fp);
return (0);
}
writemat(char *fname, int *mat, int n){
FILE *fp;
int i, j;

if ((fp = fopen(fname, "w")) == NULL)


return (-1);
for (i = 0; i < n; fprintf(fp, "\n"), i++)
for (j = 0; j < n; j++)
fprintf(fp, "%d ", _mat(i, j));
fclose(fp);
return (0);
}
void Print_Matrix(int x, int y, int myid, int S, int *M){
int i,j;
printf("myid:%d\n",myid);
for(i=0; i<x; i++)
{
for(j=0; j<y; j++)
printf(" %d ",M[i*S+j]);

16
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

printf("\n");
}
}
Algoritma Fox
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <mpi.h>

typedef struct{
int p; //#prosesor
int mypid; //procesor id
int oldpid; //id prosesor yg lama
int myrow; //jumlah baris
int mycol; //jumlah kolom
int q; //ukuran blok
MPI_Comm comm; //communicator utk seluruh blok
MPI_Comm r_comm;//communicator utk blok baris
MPI_Comm c_comm;//communicator utk blok kolom
}GRID_TOP_TYPE;

/*fungsi yang dipakai*/


double **inMatrix(int i,int j,int n,double r);
void Pmatrix(int n,double **A,double **B,double **C);
void Tmatrix(int n,double **A,double **B,double **C);
void MinMatrix(double **A,double **B,int n);
void Mprint(int i,int j,int n,double **A);
void create_grid(GRID_TOP_TYPE *grid);

/*fungsi utama*/
main(int argc,char **argv){
int n1,step,k;
int source,dest;
int tag=22;
double **A,**B,**C;
double **localA,**localB,**localC,**temp_A;
double t1,t2;
MPI_Status status;

GRID_TOP_TYPE *grid;

/*start MPI*/
MPI_Init(&argc,&argv);

/*buat blok*/
grid=(GRID_TOP_TYPE *)malloc(sizeof(GRID_TOP_TYPE));
create_grid(grid);
printf("jum prosesor:%d, ukuran grid: %d\n",grid->p,grid->q);

/*baca input ukuran matrix*/


if(grid->oldpid==0){
printf("Masukkan ukuran matrix yang mau dihitung:\n");
scanf("%d",&n1);
}
MPI_Bcast(&n1,1,MPI_INT,0,MPI_COMM_WORLD);

/*bikin matrix input*/


A=inMatrix(grid->myrow,grid->mycol,n1,2.0);
B=inMatrix(grid->myrow,grid->mycol,n1,1.0);
C=inMatrix(0,0,n1,0);
localA=inMatrix(0,0,n1,0);
localB=inMatrix(grid->myrow,grid->mycol,n1,1);
localC=inMatrix(0,0,n1,0);
temp_A=inMatrix(0,0,n1,0);
printf("Matrix A:\n");
Mprint(grid->myrow,grid->mycol,n1,A);
printf("\n");
printf("Matrix B:\n");
Mprint(grid->myrow,grid->mycol,n1,B);

/*hitung address yang diperlukan untuk putaran shift*/


source=(grid->myrow+1)%grid->q;
dest=(grid->myrow+grid->q-1)%grid->q;
t1=MPI_Wtime();
for(step=0;step<grid->q;step++){
k=(grid->myrow+step)%grid->q;

17
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

/*inisialisasi blok localA dengan A*/


if(grid->mycol==k){
MinMatrix(localA,A,n1);
MPI_Bcast(localA[0],n1*n1,MPI_DOUBLE,k,grid->r_comm);

/*hitung C=localA*B dan localC=localC+C*/


Tmatrix(n1,localA,localB,C);
Pmatrix(n1,C,localC,localC);}
else {
MPI_Bcast(temp_A[0],n1*n1,MPI_DOUBLE,k,grid->r_comm);
Tmatrix(n1,localA,localB,C);
Pmatrix(n1,C,localC,localC);
}
MPI_Sendrecv_replace(localB[0],n1*n1,MPI_DOUBLE,dest,tag,source,tag,grid-
>c_comm,&status);
}
t2=MPI_Wtime();

printf("\n");
printf("hasilnya:\n");
Mprint(grid->myrow,grid->mycol,n1,C);

printf("\n");
printf("\n\nWaktu yang diperlukan %d processes = %lf msecs\n",grid->p,(t2-t1)/0.001);

MPI_Finalize();
}
/*fungsi untuk inisialisasi matrix*/
double **inMatrix(int i,int j,int n,double r){
int a,b;
double **p;
double *pp;

//alokasi memori untuk matrix yang dibuat


p=(double **)malloc(n*sizeof(double *));
pp=(double *)malloc(n*n*sizeof(double));
for(a=0;a<n;a++)p[a]=pp+a*n;

for(a=0;a<n;a++)
for(b=0;b<n;b++){
if(a==b)p[a][b]=r;
else if(a<b) p[a][b]=r+j;
else p[a][b]=r+i;
}
return p;
} //inisialisasi matrix
/*untuk penjumlahan matrix*/
void Pmatrix(int n,double **A,double **B,double **C){
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
C[i][j]=A[i][j]+B[i][j];
}
/*untuk mengkalikan matrix*/
void Tmatrix(int n,double **A,double **B,double **C){
int i,j,k;
for(i=0;i<n;i++)
for(j=0;j<n;j++){
C[i][j]=0.0;
for(k=0;k<n;k++)
C[i][j]+=A[i][k]*B[k][j];
}
}
/*inisialisasi satu matrix dengan yang lain*/
void MinMatrix(double **A,double **B,int n){
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
A[i][j]=B[i][j];
}
/*print matrix ke layar*/
void Mprint(int i,int j,int n,double **A){
int a,b;

//printf("M[%d,%d]=\n",i,j);
for(a=0;a<n;a++)
for(b=0;b<n;b++){
printf("%8.0f ",A[a][b]);

18
Wayan Sriyasa/G651080154
Departemen Ilmu Komputer, FMIPA, IPB

if(b==n-1)printf("\n");
}
}

/*buat topologi grid*/


void create_grid(GRID_TOP_TYPE *grid){
int dim[2];
int period[2];
int coord[2];
int vary_coord[2];

/*buat topologi global*/


MPI_Comm_size(MPI_COMM_WORLD,&(grid->p));
MPI_Comm_rank(MPI_COMM_WORLD,&(grid->oldpid));

grid->q=(int)sqrt((double)grid->p);
dim[0]=dim[1]=grid->q;
period[0]=period[1]=1;

MPI_Cart_create(MPI_COMM_WORLD,2,dim,period,1,&(grid->comm));

MPI_Comm_rank(grid->comm,&(grid->mypid));
MPI_Cart_coords(grid->comm,grid->mypid,2,coord);

grid->myrow=coord[0];
grid->mycol=coord[1];

/*setting untuk communicator untuk baris dan kolom*/


vary_coord[0]=0;vary_coord[1]=1;
MPI_Cart_sub(grid->comm,vary_coord,&(grid->r_comm));
vary_coord[0]=1;vary_coord[1]=0;
MPI_Cart_sub(grid->comm,vary_coord,&(grid->c_comm));
}

19

You might also like