Professional Documents
Culture Documents
Στη περίπτωσή μας, είτε χρησιμοποιούμε έναν από τους υπολογιστές του εργαστηρίου ή ένα
απομακρυσμένο σύστημα, συνδεόμαστε ως mpiuser με το front-end του cluster με ssh
$ssh mpiuser@195.251.209.11
Συνδεόμαστε στο home directory του mpiuser, ο οποίος, αποτελεί τμήμα ενός καταλόγου mirror
που προσαρτάται (mounted) μέσω nfs σε όλους τους κόμβους που ανήκουν στο cluster. Επομένως,
ως mpiuser, από οποιοδήποτε σύστημα και αν συνδεθείτε θα καταλήξετε στο ίδιο home directory,
mpiuser@eleni:~$ pwd
/mirror/mpiuser
Τη πρώτη φορά που θα συνδεθούμε δημιουργούμε έναν υποκατάλογο με όνομα τον login name μας
(itXXXX ή maiXXXX). Από εδώ και στο εξής εργαζόμαστε σε αυτό το κατάλογο. Δεν αφήνουμε
'σκουπίδια' στο home directory, ούτε διαγράφουμε αρχεία που υπάρχουν εκεί.
Αν στο ssh προσθέσουμε την επιλογή -Χ τότε η σύνδεση επιτρέπει και τη χρήση απομακρυσμένων
εφαρμογών γραφικών. Έτσι μπορούμε να δουλέψουμε σε απομακρυσμένο editor ή άλλο
προγραμματιστικό περιβάλλον (πχ απομακρυσμένο eclipse). Γενικά η λύση αυτή δε συνιστάται σε
απομακρυσμένες συνδέσεις (εκτός εργαστηρίου).
Αν ο τοπικός μας υπολογιστής έχει λειτουργικό σύστημα MS-Windows τότε μια λύση είναι η
χρήση putty για ssh client. H χρήση απομακρυσμένων γραφικών (σε αντιστοιχία με το ssh -X)
απαιτεί χρήση xming σε συνδυασμό με putty.
Μια άλλη λύση (πιθανότατα η πιο βολική) είναι η χρήση τοπικού editor σε συνδυασμό με
απομακρυσμένη αποθήκευση και εκτέλεση. Για το σκοπό αυτό μπορούμε να χρησιμοποιήσουμε
λογισμικά που συνδυάζουν sftp και ssh. Στην ουσία συνδεόμαστε μέσω ssh στον
απομακρυσμένο/δικτυακό κατάλογο mirror και στη συνέχεια, με χρήση τοπικών εφαρμογών,
γράφουμε το πρόγραμμά μας, το αποθηκεύουμε στο απομακρυσμένο σύστημα αρχείων και το
εκτελούμε εκεί. Τέτοιες λύσεις προσφέρουν εφαρμογές όπως το filezilla, gftp αλλά και η 'Σύνδεση
με απομακρυσμένο εξυπηρετητή' στους σταθμούς εργασίας Ubuntu.
mpiuser@eleni:~$ who
mpiuser pts/0 20101011 19:19 (pdp01)
mpiuser pts/1 20101012 09:07 (kmarglaptop.local)
mpiuser pts/2 20101011 19:19 (pdp10)
mpiuser pts/5 20101011 19:21 (pdp12)
mpiuser pts/6 20101011 19:21 (pdp11)
mpiuser pts/7 20101011 19:30 (pdp04)
mpiuser pts/9 20101011 19:22 (pdp09)
Εδώ βλέπουμε αρκετούς 'παλιούς' χρήστες, που σημαίνει οτι μάλλον ξεχάσαν να αποσυνδεθούν με
exit, αλλά μπορούμε να ελέγξουμε τι εκτελούν με
mpiuser@eleni:~$ ps u mpiuser
PID TTY TIME CMD
19947 ? 00:00:00 sshd
19948 pts/0 00:00:00 bash
20137 ? 00:00:00 sshd
20138 pts/2 00:00:00 bash
20431 ? 00:00:00 sshd
20432 pts/5 00:00:00 bash
20534 ? 00:00:00 sshd
20535 pts/6 00:00:00 bash
20814 ? 00:00:00 sshd
20815 pts/9 00:00:00 bash
20883 ? 00:00:01 python2.6
21006 ? 00:00:00 sshd
21007 pts/7 00:00:00 bash
21123 pts/7 00:00:00 nano
24528 ? 00:00:00 sshd
24529 pts/1 00:00:00 bash
24591 pts/1 00:00:00 ps
Διαπιστώνουμε οτι κανείς δε κανει χρήση του MPI, άρα είναι παλιές συνδέσεις.. Δε τους κλείνουμε,
αν θέλουμε ενημερώνουμε το διαχειριστή (kmarg@uom.gr) να τους 'καθαρίσει'.
Ηθικό δίδαγμα: όταν τελειώνουμε τη δουλειά μας αποσυνδεόμαστε από το front-end με exit.
(ii) Ελέγχουμε αν ο MPI daemon είναι σε λειτουργία. O δαίμονας λέγεται mpd, και ο έλεγχος
γίνεται με τη εντολή
mpiuser@eleni:~$ mpdtrace
eleni
titan
ikaros
pdp01
pdp04
pdp10
pdp11
pdp12
pdp09
pdp03
pdp02
pdp08
pdp07
pdp05
pdp06
Αν ο mpd εκτελείται μας απαντά με τη λίστα των ενεργών κόμβων του συστήματος όπως
παραπάνω. Αν δεν εκτελείται μας ενημερώνει σχετικά
mpiuser@eleni:~$mpdtrace
mpdtrace: cannot connect to local mpd (....); possible causes:
1. no mpd is running on this host
2. an mpd is running but was started without a "console" (n option)
In case 1, you can start an mpd on this host with:
mpd &
and you will be able to run jobs just on this host.
For more details on starting mpds on a set of hosts, see
the MPICH2 Installation Guide.
mpiuser@eleni:~$ mpdboot n 15
που σημαίνει οτι συνδέουμε 15 υπολογιστές στο cluster μας, το fronr-end eleni και 14 nodes, τα
titan, ikaros και από pdp01 έως pdp12. Το αρχείο mpd.hosts που βρίσκεται στο home directory του
mpiuser δηλώνει τα συστήματα όπου θα εκτελέσουν τον mpd δαίμονα (θα είναι στο mpd ring). Σε
πεπίπτωση που κάποιο σύστημα παρουσιάσει βλάβη το 'ακυρώνουμε' απλά θέτοντας ένα #
μπροστά από το όνομά του στο αρχείο mpd.hosts. Στη συνέχεια εκτελούμε
mpiuser@eleni:~$ mpdallexit
mpiuser@eleni:~$ mpdboot n 14
ώστε να ξανα-ξεκινήσει σε όλα τα συστήματα εκτός από αυτό που είχε πρόβλημα.
Η εντολή mpdhelp δίνει κάποιες απλές πληροφορίες για τη διαχείριση του mpd
mpiuser@eleni:~$ mpdhelp
The following mpd commands are available. For usage of any specific one,
invoke it with the single argument help .
mpd start an mpd daemon
mpdtrace show all mpd's in ring
mpdboot start a ring of daemons all at once
mpdringtest test how long it takes for a message to circle the ring
mpdexit remove one mpd from the ring
mpdallexit take down all daemons in ring
mpdcleanup repair local Unix socket if ring crashed badly
mpdlistjobs list processes of jobs (a or all: all jobs for all users)
mpdkilljob kill all processes of a single job
mpdsigjob deliver a specific signal to the application processes of a job
mpiexec start a parallel job
Each command can be invoked with the help argument, which prints usage
information for the command without running it.
Λογικά τα παραπάνω βήματα θα τελειώνουν πολύ γρήγορα, δηλαδή οι εντολές who και mpdtrace
θα δείχνουν οτι το σύστημα λειτουργεί χωρίς ιδιαίτερο φόρτο.
mpiuser@eleni:~/kmarg$ nano hello.c
GNU nano 2.2.2 File: hello.c Modified
#include "mpi.h"
#include <stdio.h>
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, rc;
rc = MPI_Init(&argc,&argv);
if (rc != MPI_SUCCESS) {
printf ("Error starting MPI program. Terminating.\n");
MPI_Abort(MPI_COMM_WORLD, rc);
}
MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
printf ("Number of tasks= %d My rank= %d\n", numtasks,rank);
/******* do some work *******/
MPI_Finalize();
}
^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Pos
^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Text^T To Spell
Δέχεται copy-paste από άλλες εφαρμογές, σώζει (χωρίς να τερματίσει με ^0, τερματίζει με ^Χ.
Μπορείτε να διορθώνετε το πρόγραμμα στο προσφιλές σας περιβάλλον (τοπικά) και να το
μεταφέρετε με copy-paste ή με sftp στο front-end μόνο για την μεταγλώττιση και εκτέλεση.
Προτεινόμενες λύσεις Οι εφαρμογές putty, filezilla ή winscp.
Για να παραχθεί εκετελέσιμο με όνομα hello. Η εντολή mpicc ακολυθεί τις συμβάσεις της gcc. Για
παράδειγμα αν το πρόγραμμά μας χρησιμοποιεί τη βιβλιοήκη math.h τότε η μεταγλώττιση πρέπει
να έχει τη μορφή
mpiuser@eleni:~/kmarg$ mpicc lm o hello hello.c
Για την εκτέλεση σε 4 κόμβους γράφουμε
mpiuser@eleni:~/kmarg$ mpiexec n 4 ./hello
Προσοχή στο ./ για να αναζητήσει το εκτελέσιμο στο τρέχοντα κατάλογο. Παρατίθεται σύντομη
βοήθεια για το mpiexec.
mpiuser@eleni:~$ mpiexec help
usage:
mpiexec [h or help or help] # get this message
mpiexec file filename # (or f) filename contains XML job
description
mpiexec [global args] [local args] executable [args]
where global args may be
l # line labels by MPI rank
bnr # MPICH1 compatibility mode
machinefile # file mapping procs to machines
s <spec> # direct stdin to "all" or 1,2 or 24,6
1 # override default of trying 1st proc locally
ifhn # network interface to use locally
tv # run procs under totalview (must be ...
tvsu # totalview startup only
gdb # run procs under gdb
m # merge output lines (default with gdb)
a # means assign this alias to the job
ecfn # output_xml_exit_codes_filename
recvtimeout <integer_val> # timeout for recvs to fail (e.g. from mpd ..
g<local arg name> # global version of local arg (below) and...
n <n> or np <n> # number of processes to start
wdir <dirname> # working directory to start in
umask <umask> # umask for remote process
path <dirname> # place to look for executables
host <hostname> # host to start on
soft <spec> # modifier of n value
arch <arch> # arch type to start on (not implemented)
envall # pass all env vars in current environment
envnone # pass no env vars
envlist <list of env var names> # pass current values of these vars
env <name> <value> # pass this value of this env var
mpiexec [global args] [local args] executable args : [local args] executable...
mpiexec gdba jobid # gdbattach to existing jobid
mpiexec configfile filename # filename contains cmd line segs as lines
(See User Guide for more details)
Examples:
mpiexec l n 10 cpi 100
mpiexec genv QPL_LICENSE 4705 n 3 a.out
mpiexec n 1 host foo master : n 4 host mysmp slave
Επισημαίνουμε οτι τυπικά μόνο το front-end έχει επικοινωνία με το χρήστη. Διαπιστώνουμε οτι
υπάρχουν πολλοί εναλλακτικοί τρόποι εκτέλεσης αλλά ξεπερνούν την απλή χρήση του MPI. Ένα
ενδεικτικό machine file με όνομα mf (ή mfcore) μπορείτε να βρείτε στο home directory του
mpiuser. Ο αριθμός δίπλα στο όνομα του μηχανήματος ενημερώνει το σύστημα εκτέλεσης για τον
αριθμό επεξεργαστών ανά σύστημα.
mpiuser@eleni:~$ cat mf
eleni:4
titan:4
ikaros:16
pdp01:2
pdp02:2
pdp03:2
pdp04:2
pdp05:2
pdp06:2
pdp07:2
pdp08:2
pdp09:2
pdp10:2
pdp11:2
pdp12:2
εναλλακτικά μπορεί να διαπιστώσετε οτι το όνομα του υπολογιστή επαναλαμβάνεται για τόσες
γραμμές όσοι είναι οι επεξεργαστές του (αρχείο mfm). Μια κυκλική ανάθεση των εργασιών (μια
ανά υπολογιστή, κατ' αρχήν) μπορεί να επιτευχθεί με το αρχείο mfsingle. Το αρχείο mf32 αποκλείει
τα titan, ikaros που έχουν λειτουργικό 64 bits. Παρακάτω, στον υβριδικό προγραμματισμό,
συζητούμε τη χρήση του machinefile.
mpiuser@eleni:~/kmarg$ mpiexec machinefile mf32 n 4 ./hello > hello.results
ώστε να κατευθύνουμε τα αποτελέσματα σε ένα αρχείο αντί στο stdout. Ανάλογα μπορούμε να
ανακατευθύνουμε το stdin. Στις παρακάτω εντολές η επιλογή -machinefile mf32 παραλείπεται για
λόγους συντομίας.
mpiuser@eleni:~/kmarg$ mpiexec n 4 ./hello < hello.input > hello.results
10 Σύνδεση
Για τη χρήση του OpenMP δεν απαιτείται ιδιαίτερη υποδομή, παρά μόνο ένα τουλάχιστο διπύρηνο
σύστημα με σύγχρονο μεταγλωττιστή C. Επιμένως μπορούμε να συνδεθούμε απομακρυσμένα είτε
ως pdpuser είτε ως mpiuser στο 195.251.209.11 (eleni). Φυσικά αν συνδεθούμε ως pdpuser θα
βλέπουμε το home directory του pdpuser, άρα καλό είναι να δημιουργήσουμε πάλι έναν
υποκατάλογο με το login name μας.
Για τοπική σύνδεση, αν συνδεθούμε ως pdpuser θα έχουμε πρόσβαση σε έναν από τους διπύρηνους
κόμβους pdp01 έως pdp12 και όχι τετραπύρηνο στο eleni. Επομένως, αν θέλετε να σώσετε στο
τέλος τη δουλειά σας θα πρέπει να την αποθηκεύσετε κάπου με κάπως περισσότερη ασφάλεια, πχ
στον υποκατάλογό σας στο eleni.
11 Έλεγχος OpenMP
Ο μόνος έλεγχος που απαιτείται είναι να βεβαιωθούμε οτι ο μεταγλωττιστής C υποστηρίζει
OpenMP. Στη περίπτωσή μας, για τη gcc
pdpuser@eleni:~$ man gcc | grep [oO]pen[mM][pP]
fopenmp fmsextensions trigraphs nointegratedcpp
fopenmp
Enable handling of OpenMP directives "#pragma omp" in C/C++ and
"!$omp" in Fortran. When fopenmp is specified, the compiler
generates parallel code according to the OpenMP Application Program
Interface v2.5 <http://www.openmp.org/>. This option implies
pdpuser@eleni:~$ gcc v
Using builtin specs.
Target: i486linuxgnu
Configured with: ../src/configure v withpkgversion='Ubuntu 4.4.34ubuntu5'
withbugurl=file:///usr/share/doc/gcc4.4/README.Bugs enablelanguages=c,c+
+,fortran,objc,objc++ prefix=/usr enableshared enablemultiarch ......
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.34ubuntu5)
pdpuser@eleni:~$ gcc o hello fopenmp hello.c
# include <stdlib.h>
# include <stdio.h>
# include <omp.h>
int main ( int argc, char *argv[] )
{
int nthreads, size, rank;
size = omp_get_num_procs ( );
printf ( "There are %d processors\n", size);
size = omp_get_max_threads ( );
printf ( "By default there are %d threads\n", size);
nthreads = 4;
omp_set_num_threads ( nthreads );
#pragma omp parallel private ( rank )
{
rank = omp_get_thread_num ( );
printf ( " This is thread %d\n", rank );
}
return 0;
}
Κατα τα λοιπά ισχύουν όσα ήδη αναφέρθηκαν για ανακατεύθυνση αρχείων και shell scripts.
pdpuser@eleni:~$ mpicc o hello fopenmp hello.c
# include <stdlib.h>
# include <stdio.h>
# include <omp.h>
# include "mpi.h"
int main ( int argc, char *argv[] )
{
int thread_size, thread_rank, proc_size, proc_rank;
MPI_Init( &argc, &argv );
MPI_Comm_size( MPI_COMM_WORLD, &proc_size );
MPI_Comm_rank( MPI_COMM_WORLD, &proc_rank );
thread_size = omp_get_max_threads ( );
omp_set_num_threads ( thread_size );
#pragma omp parallel private ( thread_rank )
{
rank = omp_get_thread_num ( );
printf( "Hello world from process %d of %d\n. This node has %d cores. This
is thread %d", proc_rank, proc_size, thread_size, thread_rank);
}
MPI_Finalize();
return 0;
}
Η εκτέλεση επιτυγχάνεται ακριβώς όπως και στη περίπτωση προγραμμάτων MPI, δηλαδή με κλήση
της mpiexec.
14 Χρήση machinefile
Σε αυτό το σημείο είναι ενδιαφέρον να σχολιαστούν οι εναλλακτικές δυνατότητες υβριδικού
παραλληλισμού που μπορούν να επιτευχθούν από το συνδυασμό ΜPI, OpenMP και συστήματος
εκτέλεσης του MPI (δηλαδή του mpd δαίμονα).
Όπως έχει εξηγηθεί παραπάνω, τo αρχείο mpd.hosts ενημερώνει το δαίμονα mpd για τους
διαθέσιμους πυρήνες ανά υπολογιστή. Όταν εκτελούμε μια εργασία MPI με την mpiexec οι
πληροφορίες του δαίμονα mpd, περνούν στο σύστημα εκτέλεσης. Έτσι η απεικόνιση εργασιών
γίνεται τυχαία, με βάση τις πληροφορίες του αρχείου mpd.hosts. Μπορεί επομένως, εν επιλέξουμε
mpiexec -n 4 να γίνει ανάθεση 2 εργασιών ΜPI στο eleni και απο μια σε άλλα δύο συστήματα κλπ.
Κάθε εκτέλεση μπορεί να έχει και διαφορετική ανάθεση εργασιών.
Μέχρι τώρα χρησιμοποιήσαμε την επιλογή -machinefile mf32 για να αποφύγουμε την ετερογένεια
των λειτουργικών συστημάτων (32 και 64 bits). Για να χρησιμοποιήσουμε αυτά τα συστήματα
πρέπει να κάνουμε static linking ώστε το εκτελέσιμο να μην αναζητά ανύπαρκτη βιβλιοθήκη 32 bits
σε συστήματα των 64 bits. Παρακάτω παρατίθεται ένα ενδεικτικό Makefile το οποίο αντικαθιστά
την εντολή mpicc -fopenmp.
CC = gcc
TARGET = exec
OBJS= main.o first.o second.o
CPPFLAGS=DHAVE_CONFIG_H DHAVE_STRING_H I. I/mirror/mpich2/include Wall O2
funrollloops fopenmp
LDFLAGS=L/mirror/mpich2/lib L/mirror/mpich2/lib lopa lpthread lrt static
lmpich
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CPPFLAGS) $(OBJS) o $(TARGET) $(LDFLAGS)
main.o: main.c
$(CC) $(CPPFLAGS) c main.c
first.o: first.c
$(CC) $(CPPFLAGS) c first.c
second.o: second.c
$(CC) $(CPPFLAGS) c second.c
clean:
rm f *.o *.d $(TARGET) core
mpiexec machinefile mfm n 8 ./hello
Η πρώτη μέθοδος υβριδικού προγραμματισμού είναι ρητή, εκφραστική και πιο αποδοτική. Απαιτεί
αλλαγή του κειμένου προγράμματος και χρήση OpenMP. Η δεύτερη μέθοδος είναι έμμεση, εύκολη
και λιγότερο αποδοτική. Δεν απαιτεί αλλαγή στο πρόγραμμα και χρήση OpenMP.
Τόσο η σχεδίαση όσο και η εκσφαλμάτωση της εφαρμογής καλό είναι να χωρίζεται σε επι μέρους
επίπεδα. Εδώ παρουσιάζεται μια προσέγγιση top-down.
Αρχικοποίηση παράλληλου περιβάλλοντος
Εισαγωγή, Προεπεξεργασία δεδομένων από το Κυρίως Πρόγραμμα
/* Αρχή παράλληλης εκτέλεσης και μετρήσεων */
Διανομή ή Ανάθεση Δεδομένων στις Παράλληλες Εργασίες από το Κυρίως Πρόγραμμα
Εκτέλεση Υπολογισμών (μπορεί να περιλαμβάνουν επικοινωνία ή επαναλήψεις)
Συλλογή Δεδομένων από τις Παράλληλες Εργασίες προς το Κυρίως Πρόγραμμα
/* Τέλος παράλληλης εκτέλεσης και μετρήσεων */
Μετάεπεξεργασία και Εξαγωγή δεδομένων από το Κυρίως Πρόγραμμα
Κλείσιμο του παράλληλου περιβάλλοντος
21 Αρχικός σχεδιασμός
Πρώτα πρέπει να αποφασίσουμε
Επιμερισμός
• Ποιούς υπολογισμούς θα εκτελεί το Κυρίως Πρόγραμμα και ποιούς οι Εργασίες;
• Ποια δεδομένα είναι διαμοιραζόμενα (καθολικά) και ποια ιδιωτικά (τοπικά);
• Ποια δεδομένα θα αποσταλούν / ανατεθούν;
• Με ποιες δομές δομές δεδομένων τα αποθηκεύει το Κυρίως Πρόγραμμα και με ποιες οι
Εργασίες;
Επικοινωνία
• Ποιες τεχνικές διανομής / ανάθεσης δεδομένων θα χρησιμοποιηθούν;
• Ποιες τεχνικές συλλογής δεδομένων θα χρησιμοποιηθούν;
• Ποιές τεχινικές επικοινωνίας και συγχρονισμού απαιτούνται κατά την εκτέλεση των
υπολογισμών;
22 Υπολογισμοί
Οι υπολογισμοί μπορούν να ελεγχθούν σε ακολουθιακό περιβάλλον, αφού στον πυρήνα της
εφαρμογής μας υπάρχει ένας ακολουθιακός κώδικας που εκτελείται από κάθε Εργασία, όμοιος ή
διαφορετικός. Δημιουργούμε το κατάλληλο περιβάλλον με απλές αναθέσεις τιμών σε δομές
δεδομένων ώστε να βρισκόμαστε στην ίδια ακριβώς κατάσταση που θα βρεθούμε μετά από την
διανομή/ανάθεση δεδομένων. Κατόπιν εκτελούμε τους υπολογισμούς και ελέγχουμε το αποτέλεσμα
που θα πρέπει να συλλεχθεί. Ελέγχουμε διάφορους πιθανούς συνδυασμούς τιμών (πχ για διάφορες
τιμές rank, size, tid, num_threads, μέγεθος προβλήματος) ώστε να είμαστε σίγουροι οτι δε θα
προκύψουν δείκτες εκτός ορίων κλπ.
23 Επικοινωνία
Κατόπιν πρέπει να διασφαλιστεί η σωστή διανομή / ανάθεση και συλλογή δεδομένων, δηλαδή η
λειτουργία της επικοινωνίας των εργασιών. Στη συνέχεια η επικοινωνία ελέγχεται με απλά ψευδο-
δεδομένα ώστε να βεβαιωθούμε οτι τα δεδομένα μεταφέρονται σωστά από-προς το Κυρίως
Πρόγραμμα. Η επικοινωνία ελέγχεται αρχικά με τον ελάχιστο αριθμό Παράλληλων Εργασιών. Ο
απλούστερος έλεγχος μπορεί να γίνει με την εμφάνιση δεδομένων πριν και μετά την επικοινωνία ή
ανάθεση. Αν η επικοινωνία επιτύχει τότε δοκιμάζουμε με μεγαλύτερους όγκους δεδομένων και
αριθμούς Εργασιών.
24 Αρχικοποιήσεις
Είναι σημαντικό να αρχικοποιούμε δομές δεδομένων πριν τις χρησιμοποιήσουμε σε επικοινωνία
ώστε να μην έχουμε null pointers ή περίεργες αριθμητικές τιμές.
26 Διαχείριση Αρχείων
Σε περίπτωση εκτέλεσης προγράμματος μόνο με OpenMP σε τοπικό κατάλογο, ισχύουν αυτά που
γνωρίζουμε από το συμβατικό προγραμματισμό. Σε περίπτωση χρήσης MPI ή υβριδικού
προγράμματος, οι αναγνώσεις / εγγραφές σε αρχεία, εφ' όσον βρισκόμαστε στο κατάλογο mirror,
εκτελούνται με τη βοήθεια του nfs, δηλαδή φαίνονται ως 'τοπικές' για όλους τους κόμβους του
cluster. Αυτό σίγουρα επιβαρύνει τη διαδικασία ανάγνωσης εγγραφής, αλλά είναι μάλλον λιγότερο
επιβαρυντικό από τη ρητή χρήση διανομής και συλλογής μέσω του προγράμματος. Η χρήση
πραγματικά τοπικών αρχείων σε κάθε κόμβο μπορεί να επιτευχθεί με χρήση απολύτου ονόματος
διαδρομής (πχ /home/pdpuser/file_name). Φυσικά θα πρέπει να υπάρχουν τα κατάλληλα
δικαιώματα και τα αρχεία να έχουν προ-αποθηκευτεί.
27 Διαχείριση μνήμης
Συνήθως τα δεδομένα που χρησιμοποιούμε είναι αρκετά μεγάλα ώστε δοκιμάζουν τα όρια αντοχής
των συστημάτων. Για παράδειγμα ένα αρχείο 2Gbytes αν φορτωθεί σε πίνακα στη RAM θα
καταλάβει μεγάλο μέρος της διαθέσιμης RAM. Ένας δι-διάστατος πίνακας 10000 αριθμών διπλής
ακρίβειας απαιτεί 8 * 10^8 bytes ή περίπου 2^3 * 2^28 = 2 Gbytes!! Αν σκεφτούμε οτι το address
space σε σύστημα 32bit είναι 4 Gbytes καταλαβαίνουμε οτι αυτό αποτελεί και ένα λογικό – και
φυσικό όριο.
Η στατική ανάθεση μνήμης, της μορφής int a[N]; περιορίζεται από το μέγεθος του τμήματος
δεδομένων που εκχωρεί το σύστημα σε μια διεργασία.
Η δυναμική ανάθεση μνήμης, με χρήση malloc(), περιορίζεται από τα όρια ης υλοποίησης της
γλώσσας προγραμματισμού και του λειτουργικού συστήματος. Τα όρια αυτά μπορούν να ελεγχθούν
με τη συνάρτηση getrlimits() που επιστρέφει μια δομή με μέγιστες τιμές των διαθέσιμων πόρων.
Ειδικά για τη malloc() καλό είναι να θυμόμαστε οτι είναι δουλειά του προγραμματιστή να ελέγξει
αν έχει όντως δεσμευθεί η απαιτούμενη μνήμη, έτσι ώστε να αποφύγουμε στη συνέχεια το
Segmentation Fault. Αν η malloc() αποτύχει ή δε καταταφέρει να δεσμεύσει την απαιτούμενη
μνήμη επιστρέφει δείκτη NULL.
Η χρήση δευτερεύουσας μνήμης δεν γίνεται αυτόματα, αλλά πρέπει να δηλωθεί ρητά με τη βοήθεια
της συνάρτησης mmap(), η οποία απεικονίζει μέρος του χώρου διευθύνσεων μιας διεργασίας σε
δευτερεύουσα μνήμη (αρχείο). Στην ουσία προγραμματίζουμε στο swap space με οτι αυτό μπορεί
να σημαίνει για την απόδοση του προγράμματος.
Μια πιο απλή λύση είναι η εξής: κρατούμε τα δεδομένα μας σε αρχείο και τα φορτώνουμε
τμηματικά, είτε σε έναν υπολογιστή (περίπτωση OpenMP) είτε σε διαφορετικούς (MPI με χρήση
nfs). Μετά το τέλος της επεξεργασίας σώζουμε τα αποτελέσματα και φορτώνουμε τα επόμενα
τμήματα.
28 Βελτίωση απόδοσης
Μετά τη διασφάλιση της ορθής λειτουργίας του προγράμματος και την απεικόνιση των πρώτων
αποτελεσμάτων μπορούμε να προσπαθήσουμε να βελτιώσουμε την απόδοσή του με διάφορες
τεχνικές με στόχο τη βέλτιστη ομαδοποίησης και απεικόνισης των υπολογισμών. Μελετούμε
• Τη σχέση ακολουθιακού προς παράλληλο τμήμα του υπολογισμού
• Τις δυνατότητες κλιμάκωσης των υπολογισμών σε σχέση με τον αριθμό των επεξεργαστών
και το μέγεθος του προβλήματος
• Τη σχέση επικοινωνίας και υπολογισμού, όπου στην επικοινωνία μπορούμε να περιλάβουμε
και την προσπέλαση σε διαμοιραζόμενη μνήμη.
• Θέματα εξισορρόπησης υπολογιστικού φόρτου.
3 Απεικόνιση αποτελεσμάτων
Συνήθως τα αποτελέσματα εκτέλεσης των παράλληλων προγραμμάτων περιλαμβάνουν μετρήσεις
απόδοσης. H εφαρμογή gnuplot μπορεί να βοηθήσει στην γρήγορη παραγωγή γραφικών
απεικονίσεων των αποτελεσμάτων αυτών.
31 Προετοιμασία
Πρώτα ελέγχουμε τα αποτελέσματα στην οθόνη. Τα αποτελέσματα πρέπει να εμφανίζονται στην
οθόνη σε στήλες, με τους αριθμούς χωρισμένους με κενά ή tab, χωρίς άλλα επεξηγηματικά σχόλια
μεταξύ των αριθμών. Κάθε στήλη πρέπει να αντιστοιχεί σε μια ποσότητα, συνήθως η πρώτη στήλη
θα απεικονιστεί στον άξονα Χ του διαγράμματος ενώ οι άλλες στήλες αντιστοιχούν στις ποσότητες
που θα απεικονιστούν στον άξονα Υ. Σχόλια επιτρέπονται σε ξεχωριστές γραμμές. Οι γραμμές
αυτές ξεκινούν με #. Παράδειγμα
# Παράδειγμα αρχείου αποτελεσμάτων για N = 1000 P =1
# P Total T Comp T Comm T
1 10 10 0
# Παράδειγμα αρχείου αποτελεσμάτων για N = 1000 P =2
# P Total T Comp T Comm T
2 9 7 2
# Παράδειγμα αρχείου αποτελεσμάτων για N = 1000 P =4
# P Total T Comp T Comm T
4 6 3 3
# Παράδειγμα αρχείου αποτελεσμάτων για N = 1000 P =8
# P Total T Comp T Comm T
8 6 2 4
Ένα τέτοιο αρχείο θα μπορούσε να παραχθεί από ένα shell script της μορφής
#!/bin/bash
mpiexec n 1 ./hello < hello.input > hello.results
mpiexec n 2 ./hello < hello.input >> hello.results
mpiexec n 4 ./hello < hello.input >> hello.results
mpiexec n 8 ./hello < hello.input >> hello.results
το οποίο έχουμε αποθηκεύσει ως hello.run
32 Χρήση gnuplot
To gnuplot μπορεί να κληθεί από τη γραμμή εντολών. Απαντά με τη προτροπή του:
gnuplot>
gnuplot> plot "hello.results" using 1:3 title 'Computation' with lines
το οποίο θα παράγει το επιθυμητό γράφημα, για τις στήλες 1 στον άξονα Χ, 3 στον άξονα Υ και με
χρήση γραμμής, και τίτλό Computation. Για απεικόνιση περισσότερων στηλών
gnuplot> plot "hello.results " using 1:2 title 'Total' with lines,\
> "hello.results" u 1:3 t 'Comp' w l,\
> "hello.results" u 1:4 t 'Comm' w l
gnuplot>
Η απεικόνισή μας έχει αποθηκευτεί στο αρχείο hellp.gif. Αντί για gif θα μπορούσαμε να διαλέξουμε
jpeg, png, postscript, svg κλπ, ανάλογα με την εφαρμογή στην οποία θέλουμε να εισάγουμε τη
γραφική απεικόνιση.
Οι δυνατότητες του gnuplot είναι πολλές. Σύντομες εισαγωγές στο gnuplot μπορείτε να βρείτε εδώ
http://www.it.uom.gr/teaching/gnuplot/
αλλά και στο Διαδίκτυο. Επίσης υπάρχουν γραφικές διεπαφές, όπως το PlotDrop που διευκολύνουν
τη χρήση του gnuplot με ποντίκι και μενού.
33 Gnuplot scripts
Οι εντολές του gnuplot είναι ουσιαστικά σενάρια που εκτελούνται. Επομένως μπορoύμε να
εκτελέσουμε την ίδια εργασία με τη βοήθεια ενός σεναρίου gnuplot. Πρώτα ελέγχουμε το path της
εφαρμογής
mpiuser@eleni:~$ which gnuplot
/usr/bin/gnuplot
#!/usr/bin/gnuplot
set terminal gif
set output "hello.gif"
plot "hello.results" using 1:2 title 'Total' with lines,\
"hello.results" u 1:3 t 'Comp' w l,\
"hello.results" u 1:4 t 'Comm' w l