1. MPI (Message Passing Interface)
MPI atau Mesage Passing Interface adalah spesifikasi yang perlu diterapkan pengembang dan pengguna pemrograman parallel. Sedangkan pustaka yang mengimplementasi spesifikasi tersebut dapat kita peroleh misalnya dari bahasa C/C++. Untuk menggunakan pustaka tersebut kita hanya tinggal mendeklarasinya di awal program seperti berikut ini.
#include "mpi.h"
Secara umum, pemrograman parallel menggunakan spesifikasi MPI membutuhkan tiga tahapan. Hal ini terlepas dari kebutuhan lain terkait eksekusi seperti mem-boot layanan ini. Ketiganya adalah:
- Inisialisasi
- Dekomposisi, distribusi dan pengambilan kembali sub pekerjaan
- De-inisialisasi
Bagaimana ketiganya diterapkan dalam C/C++, berikut adalah contoh prrogram sederhana.
Program berikut ini hanya bertugas menampilkan karakter/informasi ke layar oleh masing-masing node yang terlibat dalam komunkasi MPI. Kode sumber pertama dibuat dalam C.
#include <stdio.h>
#include "mpi.h"
int main(int argc, char ** argv) {
int p;
int id;
double wtime;
//Inisialisasi MPI
MPI_Init(&argc,&argv);
//Mendapatkan id dan jumlah proses
MPI_Comm_size(MPI_COMM_WORLD,&p);
MPI_Comm_rank(MPI_COMM_WORLD,&id);
wtime=MPI_Wtime();
//Mendistribusi pekerjaan
if(id==0) {
printf("MPI Hello - Master Process\n");
printf(" C / MPI version\n");
printf(" An example program\n\n");
printf(" The number of process = %d\n",p);
}
else {
printf("Process %d says 'Hello World!'\n",id);
}
if(id==0) {
printf("\n");
printf("Hello MPI - Master Process:\n");
printf(" Normal end of execution: 'Goodbye World!'\n\n");
wtime=MPI_Wtime() - wtime;
printf("Elapsed wall clock time = %g seconds\n", wtime);
}
//De-inisialisasi
MPI_Finalize();
return 0;
}
2. openMP
OpenMP (Open Multi-Processing) adalah sebuah API (application programming interface) yang mendukung multi-platform memori bersama pemrograman multiprocessing dalam C, C + +, dan Fortran, pada arsitektur prosesor paling dan sistem operasi, termasuk Linux, Unix, AIX, Solaris, Mac OS X, dan Microsoft Windows platform. Ini terdiri dari satu set arahan kompiler, rutinitas perpustakaan, dan variabel lingkungan yang mempengaruhi perilaku saat run-time
Contoh model program parallel openMP
#include <omp.h> |
#include <sdl.h> |
#include <windows.h> | |
#include <math.h> |
| |
void __putpixel(SDL_Surface* buffer, int x, int y, Uint32 color) |
{ | |
int bpp = buffer->format->BytesPerPixel; |
/* Here p is the address to the pixel we want to set */ | |
Uint8 *p = (Uint8 *)buffer->pixels + y * buffer->pitch + x * bpp; |
| |
switch(bpp) { |
case 1: | |
*p = color; |
break; | |
|
case 2: | |
*(Uint16 *)p = color; |
break; | |
|
case 3: | |
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { |
p[0] = (color >> 16) & 0xff; |
p[1] = (color >> 8 ) & 0xff; |
p[2] = color & 0xff; | |
} else { |
p[0] = color & 0xff; | |
p[1] = (color >> 8 ) & 0xff; |
p[2] = (color >> 16) & 0xff; | |
} |
break; | |
|
case 4: | |
*(Uint32 *)p = color; |
break; | |
} |
} | |
|
Uint32 __getpixel(SDL_Surface* buffer, int x, int y) | |
{ |
int bpp = buffer->format->BytesPerPixel; | |
/* Here p is the address to the pixel we want to retrieve */ |
Uint8 *p = (Uint8 *)buffer->pixels + y * buffer->pitch + x * bpp; | |
|
switch(bpp) { | |
case 1: |
return *p; | |
|
case 2: | |
return *(Uint16 *)p; |
| |
case 3: |
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) | |
return p[0] << 16 | p[1] << 8 | p[2]; |
else | |
return p[0] | p[1] << 8 | p[2] << 16; |
| |
case 4: |
return *(Uint32 *)p; | |
|
default: | |
return 0; /* shouldn't happen, but avoids warnings */ |
} | |
} |
| |
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd) |
{ | |
SDL_Surface *tmp, *screen; |
| |
int i, j, w, h; |
int nThread, tid; | |
Uint32 starttick; |
SDL_Event evt; | |
int done = 0; |
FILE *deb = fopen("debug.txt", "w"); | |
|
fprintf(deb, "start \n"); |
SDL_Init(SDL_INIT_VIDEO); |
atexit(SDL_Quit); | |
tmp = SDL_LoadBMP("alfa256.bmp"); |
w = tmp->w; |
h = tmp->h; |
screen = SDL_SetVideoMode(w, h, tmp->format->BitsPerPixel, SDL_SWSURFACE|SDL_ANYFORMAT); | |
SDL_BlitSurface(tmp, NULL, screen, NULL); |
SDL_FreeSurface(tmp); | |
tmp = screen; |
| |
if ( SDL_MUSTLOCK(tmp) ) { |
if ( SDL_LockSurface(tmp) < 0 ) { | |
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError()); |
return; | |
} |
} | |
|
fprintf(deb, "starting block \n"); | |
starttick = SDL_GetTicks(); |
#pragma omp parallel shared(tmp, w, h) | |
{ |
Uint8 r, g, b, a, tmpi; | |
int i,j; |
| |
#pragma omp for schedule(dynamic) nowait |
for (j=0; j<h; ++j){ | |
for (i=0; i<w; ++i){ |
SDL_GetRGBA(__getpixel(tmp, i, j), tmp->format, &r, &g, &b, &a); | |
tmpi = (Uint8)round(0.299 * r + 0.587 * g + 0.114 * b); |
tmpi = (tmpi>128)?255:0; | |
__putpixel(tmp, i, j, SDL_MapRGBA(tmp->format, tmpi, tmpi, tmpi, a)); |
} | |
|
SDL_UpdateRect(screen, 0, 0, 0, 0); | |
} |
} | |
|
SDL_UpdateRect(screen, 0, 0, 0, 0); | |
fprintf(deb, "end block %d\n", SDL_GetTicks()-starttick); |
| |
if ( SDL_MUSTLOCK(tmp) ) { |
SDL_UnlockSurface(tmp); | |
} |
| |
while(!done){ |
while(SDL_PollEvent(&evt)){ | |
switch(evt.type){ |
case SDL_QUIT: | |
done = 1; |
break; | |
} |
} | |
} |
|
|
fclose(deb); | |
SDL_SaveBMP(tmp, "alfagrey.bmp"); |
| |
return 0; |
} |
3. POSIX thread
POSIX Thread, biasanya disebut sebagai pthreads, adalah standar POSIX untuk thread. Standar, POSIX.1c, Thread ekstensi (IEEE Std 1003.1c-1995), mendefinisikan sebuah API untuk menciptakan dan memanipulasi thread.
Implementasi dari API yang tersedia pada banyak Unix-seperti POSIX-konforman sistem operasi seperti FreeBSD, NetBSD, OpenBSD, GNU / Linux, Mac OS X dan Solaris. DR-DOS dan Microsoft Windows implementasi juga ada: dalam subsistem SFU / SUA yang menyediakan implementasi asli dari sejumlah POSIX API, dan juga di dalam paket pihak ketiga seperti pthreads-W32, yang mengimplementasikan pthreads di atas ada Windows API.
Contoh Posix thread
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pthread.h>
#include <time.h>
#define MAX_THREAD 16 /* maximum number of threads */
#define NDIM 1024 /* number of NDIMs */
double a[NDIM][NDIM];
double b[NDIM][NDIM];
double c[NDIM][NDIM];
struct timeval tvstart, tvstop;
typedef struct
{
int id; /* identification */
int noproc; /* process */
int dim; /* number of threads */
double (*a)[NDIM][NDIM],(*b)[NDIM][NDIM],(*c)[NDIM][NDIM];
} parm;
void mm(int me_no, int noproc, int n, double a[NDIM][NDIM], double b[NDIM][NDIM], double c[NDIM][NDIM])
{
int i,j,k;
double sum;
i=me_no;
while (i<n) {
for (j = 0; j < n; j++) {
sum = 0.0;
for (k = 0; k < n; k++) {
sum = sum + a[i][k] * b[k][j];
}
c[i][j] = sum;
}
i+=noproc;
}
}
void * worker(void *arg)
{
parm *p = (parm *) arg;
mm(p->id, p->noproc, p->dim, *(p->a), *(p->b), *(p->c));
}
int main(int argc, char *argv[])
{
int j, k, noproc, me_no;
double sum;
double t1, t2;
pthread_t *threads;
parm *arg;
int n, i;
for (i = 0; i < NDIM; i++)
for (j = 0; j < NDIM; j++) {
a[i][j] = i + j;
b[i][j] = i + j;
}
if (argc < 2) {
n = MAX_THREAD;
}
else {
n = atoi(argv[1]);
}
// start the bechmark timer
gettimeofday(&tvstart, NULL);
threads = (pthread_t *) malloc(n * sizeof(pthread_t));
arg=(parm *)malloc(sizeof(parm)*n);
for (i = 0; i < n; i++) {
arg[i].id = i;
arg[i].noproc = n;
arg[i].dim = NDIM;
arg[i].a = &a;
arg[i].b = &b;
arg[i].c = &c;
pthread_create(&threads[i], NULL, worker, (void *)(arg+i));
}
for (i = 0; i < n; i++) {
pthread_join(threads[i], NULL);
}
gettimeofday(&tvstop, NULL);
double t = (tvstop.tv_sec - tvstart.tv_sec) * 1000 +
(tvstop.tv_usec - tvstart.tv_usec) * 1e-3;
printf("Pthread: %d : Dim: %d : Time: %f\n", n, NDIM, t);
free(arg);
return 0;
}