MPI. Message Passing Interface

Hochschule RheinMain Fachbereich Design Informatik Medien Master-Studiengang Informatik MPI Message Passing Interface Hausarbeit Boguslaw Adam Sylla...
4 downloads 3 Views 190KB Size
Hochschule RheinMain Fachbereich Design Informatik Medien Master-Studiengang Informatik

MPI Message Passing Interface Hausarbeit

Boguslaw Adam Sylla 20. Januar 2010

2

Inhaltsverzeichnis 1 Einleitung 1.1 Geschichtlicher Anfang von MPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 2

2 Das 2.1 2.2 2.3 2.4

Maschinenmodell von MPI Flynn’sche Taxonomie . . . . Multicomputer . . . . . . . . Cluster und NOWs . . . . . . SMPD-Konzept . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

3 3 3 4 4

3 Implementationen 3.1 Installation unter Ubuntu . . . . . . . . . . . . . . . 3.2 Shell-Commandos . . . . . . . . . . . . . . . . . . . . 3.3 Multi-Purpose Daemon . . . . . . . . . . . . . . . . . 3.3.1 Root und andere User berechtigen . . . . . . . 3.3.2 Haupt- und Nebenrechner verfügbar machen

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

6 6 6 7 7 8

4 Befehlssatz der API 4.1 Top 7 Funktionen 4.2 Hello, world! . . . 4.3 Kompilierung . . . 4.4 Ausführung . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

10 10 10 11 12

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

5 MPI-Beispiel - Integralrechnung

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

13

A Verzeichnisse 16 A.1 Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 A.2 Internetquellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1

Kapitel 1

Einleitung Die Informationstechnische Fachwelt ist sich einig darin, dass der Parallelisierung von Anwendungen die Zukunft gehört. Auch wenn derzeit an Akademien Parallelisierung meist nur als Wahlpflichtfach unterrichtet wird. Bei der Parallelisierung von Anwendungen gibt es grundsätzlich erstmal zwei Konzepte. Das Parallelisieren auf einem Rechner, das als Threading bezeichnet wird und heute üblicherweise Programme parallel auf mehreren Kernen einer CPU laufen lässt. Zum anderen gibt es noch das Parallel Processing, das das gleiche Programm verteilt auf verschiedenen CPUs laufen lässt. Letzteres ist der Bereich des Hight Performane Computing, bei dem eine sehr große Anzahl von evtl. tausenden CPUs evtl. verschiedener Rechner genutzt wird. In dem Fall spricht man auch vom Massive Parallel Processing (MPP).

1.1

Geschichtlicher Anfang von MPI

Im Jahr 1994 erschien für diesen Themenbereich der Informationstechnik ein Standard zur Interprozess-Kommunikation namens Message Passing Interface (MPI). In der Folgezeit erschien auch eine Vielzahl kommerzieller und freier Bibliotheken wie OpenMPI und MPICH, die damit eine grosse Anzahl an bestimmten Funktionen zur Programmierung paralleler Anwendungen auf Prozess-Basis bereitstellen. Im Jahr 2003 erschien die zweite Version von MPI auf die sich diese Arbeit bezieht. Die Version 3 von MPI wird aber zurzeit schon standardisiert. Zuständig dafür ist das so genannte MPI-Forum, dem viele Mitglieder von Universitäten und Unternehmen angehören.

2

Kapitel 2

Das Maschinenmodell von MPI 2.1

Flynn’sche Taxonomie

In der Flynn’schen Taxomomie, die vier einander ausschließende Kategorien kennt, passt MPI in die Kategorie Multiple-Instruction-Multiple-Data (MIMD). Das kommt daher, weil mehrere Prozesse auf mehreren CPUs mit deren eigenen lokalen Teildaten ausgeführt werden. Die Unterteilung nach Flynn ist aber nur eine grobe Unterteilung von Computer-Architekturen. Und es kommt hinzu, dass heutzutage praktische jede verteilte Rechnerarchitektur für parallele Aufgaben in die Kategorie MIMD passt. Daher sind weitere Betrachtungen nötig.

Abbildung 2.1: Multiple-Instruction-Multiple-Data (MIMD)

2.2

Multicomputer

Als Multicomputer werden Netzwerke von zu einem gedachten Großcomputer zusammengeschlossenen Computer bezeichnet. Einen Multicomputer zeichnet aus, dass er somit aus mehreren CPUs besteht und der Speicher nicht gemeinsam genutzt werden kann. Jeder angeschlossene Rechner hat seinen eigenen Speicherraum. Da es keinen gemeinsamen Speicher gibt, müssen die CPUs eines Multirechners stattdessen Nachrichten miteinander austauschen. Genau dafür ist MPI entworfen. Es gibt zwei Arten von Multicomputern, den asymmetrischen und den symmetrischen. 3

Asymmetrische Multicomputer Die eher veraltete Rechnerform mit dem Konzept des Asymmetric Multi-Processing (ASMP) zeichnet aus, dass sich Benutzer an einem zentralen Rechner anmelden müssen, um dort ihre parallelen Anwendungen starten zu lassen. An den Rechner sind dann weitere Rechner im Hintergrund angeschlossen, die die Aufgaben der Benutzer dann ausführen. Diese Hintergrundrechner müssen nicht unbedingt das gleiche Betriebssystem haben oder auf das gleiche Dateisystem zugreifen. Das dürfte aber in den meisten Fällen so sein. Der offensichtliche I/O-Flaschenhals dieser Architektur, ist aber auch deren Vorteil. Dürfen sich Benutzer nur an einem zentralen und nicht an einem beliebigen Rechner anmelden, dann ist die Lastverteilung der Aufgaben für diesen Multicomputer leichter zu managen. Deswegen wird das asymmetrische Konzept in der Praxis oft mit dem symmetrischen gemischt. Symmetrische Multicomputer Bei der Rechnerform mit dem Konzept Symmetric Multi-Processing (SMP) ist es üblich, dass sich die Benutzer an jeden angeschlossenen Rechner anmelden dürfen. Jeder Rechner hat das gleiche Betriebssystem und es gibt ein gemeinsames Dateisystem. Diese Rechnerform ist die naheliegendeste für MPI. Und es muss sich auch kein Managementproblem für die Lastverteilung ergeben, wenn eine bestimmte Implementation von MPI (wie MPICH2) zusätzliche Tools bietet, um das Task-Management zu zentralisieren. Damit kann aber auch nur eine Überlastung des Multicomputers verhindert werden. Dass jeder Benutzer zu jeder Zeit ein Maximum an Performance erhält, kann nicht garantiert werden. Es kann, bedingt durch die evtl. unterschiedlichen Rechnerarchitekturen der Teilrechner, nicht einmal eine konstante Laufzeit für ein und das selbe Programm garantiert werden.

2.3

Cluster und NOWs

Es stellt sich die Frage, ob ein Multicomputer ein Cluster oder ein Network of Workstations (NOW) ist. Eine Workstation zeichnet aus, dass sie evtl. ein anderes Betriebssystem und auch ein eigenes Dateisystem hat, als andere Workstations im Netzwerk. Wo hingegen ein Cluster eher aus identischen Rechnern mit gleichem Betriebssystem und selbem Dateisystem besteht. Diese Rechenknechte eines Clusters haben anders als Workstations meist keine peripheren Geräte wie Maus, Tastatur oder Bildschirm. MPI ist vorrangig für Cluster vorgesehen, auch wenn es sicher möglich wäre ein Workstation-Projet wie SEMI@home mit MPI zu realisieren.

2.4

SMPD-Konzept

Es stellt sich auch die Frage nach Art des Programmiermodells selbst. Bei MPI-Anwendungen ist dies das Konzept Single-Program-Multiple-Data (SPMD). Mit MPI laufen mehrere Prozesse des gleichen Programms auf verschiedenenen CPUs und nutzen dabei ihre eigenen lokal in ihren jeweiligen Speichern vorhandenen Teildaten. Die Zusammenführung aller Daten erfolgt üblicherweise zum Ende des Programms. Im gemeinsamen Quellcode einer MPI-Anwendungen werden die Prozesse durch ihre eindeutigen IDs und mit Hilfe von IF-THEN-ELSE-Ausdrücken

4

kontrolliert. Der erste Prozess mit der ID=0 führt die Berechnungsresultate zusammen und sorgt auch für die Interaktion mit dem Benutzer.

5

Kapitel 3

Implementationen 3.1

Installation unter Ubuntu

Die automatische Installation einer Implementation von MPI ist unter einem auf Debian basierenden Linux wie Ubuntu recht einfach. Zur Auswahl stehen OpenMPI und MPICH2. Im Nachfolgenden wird letzteres verwendet. MPICH2 muss auf jedem Rechner installiert werden, der Teil eines so genannten Rings aus Rechnern sein soll, die ihre CPUs zur Verfügung stellen. Will man MPI-Anwendungen auf mehr als nur seinen eigenen CPUs laufen lassen, dann kann man sich per ’ssh’ oder ’rsh’ mit einem solchen Ring verbinden und dort die Anwendung ausführen lassen, ohne MPICH2 installiert zu haben. MPICH2 selbst nutzt auch nur die Remote Shell, um Prozesse auf entfernten Rechnern auszuführen. Andere Rechner eines Rings müssen also einfach nur per ’rsh’ und damit auch ’ssh’ erreichbar sein. Es ist zu erwähnen, dass MPICH2 das Erstellen von MPI-Anwendungen in C, C++ und Fortran erlaubt. Aber es gibt auch andere MPI-Implementationen, die z.B. Python, Java oder .NET unterstützen. MPICH2 gibt es im übrigen auch für Windows. Shell bsyll001@linux:~$ sudo apt-get install mpich2

3.2

Shell-Commandos

Es werden gerade mal drei Debian-Pakete, die wirklich zu MPICH2 gehören, installiert und 7 MB belegt. Alle neuen Commandos beginnen mit ’mpi’ und sollten sofort in der Shell verfügbar sein. Das Standard-Installationsverzeichnis für Shell-Commandos ’/usr/bin’ gibt genauer Aufschluss darüber, was da eigentlich wo installiert wurde. Man sieht die Compiler-Scripte für C, C++ und Fortran. Außerdem sieht man auch die zwei zum Starten von verteilten Programmen nötigen Scripte ’mpiexec’ bzw. ’mpirun’, die synonym verwendet werden können. Das gleiche gilt für ’mpic++’ bzw. ’mpicxx’. Bei MPICH2 sind es unnötigerweise Python-Scripte, was zu den vorher erwähnten 7 MB Installationsplatz auch noch einen entsprechenden Interpreter summiert. Shell

6

bsyll001@linux:~$ mpi + + mpic++

mpicxx

mpiexec.mpich2

mpirun

mpicc

mpicxx.mpich2

mpif77

mpirun.mpich2

mpicc.mpich2

mpiexec

mpif77.mpich2

mpich2version

mpiexec.gforker

mpif90

mpic++.mpich2

mpiexec.hydra

mpif90.mpich2

Wichtig sind auch einige Commandos des Multi-Purpose Daemons. Shell bsyll001@linux:~$ mpd + + mpd

mpdcheck

mpdhelp

mpdringtest

mpdallexit

mpdcleanup

mpdkilljob

mpdroot

mpdboot

mpdexit

mpdlistjobs

mpdrun

3.3

mpdtrace

Multi-Purpose Daemon

Um MPI-Anwendungen mit mehr als einem Prozess laufen zu lassen, ist ein dafür im Hintergrund des Hauptrechners laufender Daemon nötig. Ohne den kann man eine MPI-Anwendung nur mit einem Prozess wie gewohnt in der Shell ausführen. Für einen Admin stellen sich zwei Fragen. Welche User der Linux-Systems sollen den Daemon nutzen dürfen? Und welche anderen entfernten Nebenrechner sollen für die parallele Ausführung von MPI-Anwendungen genutzt werden dürfen?

3.3.1

Root und andere User berechtigen

Jeder User, der den Multi-Purpose Daemon laufen lassen will, benötigt im Heimverzeichnis eine Konfigurationsdatei namens ’.mpd.conf’. Das gilt auch für den Root-User. Im einfachsten Fall beinhaltet diese Datei nur zwei Zeilen. Die erste gibt ein vom jeweiligen User zu wählendes Passwort an und die zweite sagt aus, ob der User eigene Daemons starten darf oder den hoffentlich laufenden Daemon des Roots nutzen soll. Das Passwort kann auch das gleiche bei allen Usern sein. Das Recht seine eigene Konfigurationsdatei zu lesen und zu schreiben, sollte jeweils auf den entsprechenden User beschenkt werden. Root-User Zunächst wird der Root konfiguriert, von dem dann alle übrigen User die gleiche Konfigurationsdatei erhalten. Shell bsyll001@linux:~$ sudo su root@linux:/home/bsyll001# echo "MPD_SECRETWORD=password" > /root/.mpd.conf root@linux:/home/bsyll001# echo "MPD_USE_ROOT_MPD=yes" >> /root/.mpd.conf root@linux:/home/bsyll001# chmod 600 /root/.mpd.conf

7

Existierende User Statt die beim Root eingerichtete Konfigurationsdatei in die Heimverzeichnisse bestimmter existierender User von Hand zu kopieren, kann man den Vorgang auch für alle User ausführen. Shell root@linux:/home/bsyll001# for x in ‘ls /home/‘; do rsync -plarv /root/.mpd.conf /home/$x/; chown $x:users /home/$x/.mpd.conf; done

Zukünftige User Sollte man in Zukunft weitere User einrichten, wäre es hilfreich, wenn die Konfigurationsdatei in deren Heimverzeichnissen dabei automatisch erzeugt werden würde. Sie muss dazu vorher nach ’/etc/skel/’ kopiert werden. Shell root@linux:/home/bsyll001# cp /root/.mpd.conf /etc/skel/ root@linux:/home/bsyll001# chmod 600 /etc/skel/.mpd.conf

3.3.2

Haupt- und Nebenrechner verfügbar machen

Hauptrechner Jeder Nebenrechner könnte seinen eigenen Daemon laufen lassen. Es ist aber leichter nur den Hauptrechner einen Daemon starten zu lassen und die Nebenrechner anzuweisen sich mit dem Daemon zu verbinden. Dadurch stehen dem Daemon dann mehrere CPUs zur Verfügung. Jeder berechtigte User, darf dann den Daemon für parallele Programme nutzen. Zunächst aber müssen außer den Users noch der Haupt- und die Nebenrechner konfiguriert werden. Dazu erhält jeder der Rechner eine weitere Konfigurationsdatei in ’/etc/’. Der Dateiname beginnt nicht mit einem Punkt. Die Datei ist also unter Linux nicht versteckt. Shell root@linux:/home/bsyll001# echo "MPD_SECRETWORD=password" > /etc/mpd.conf root@linux:/home/bsyll001# chmod 600 /etc/mpd.conf

Nebenrechner Die Datei muss von Hand auf jeden Rechner kopiert werden, da jeder Rechner seine eigene Logindaten hat. Ein Shell-Script wie weiter oben vorgestellt, um die Datei automatisch auszuteilen ist aber durchaus denkbar, wenn der Admin sein Linux-System vorher so eingerichtet hat, dass er kein Passwort für SSH-Verbindungen bei angeschlossenen Rechnern benötigt. Es folgt ein Script, das eine Datei mit Rechnernamen zum Verteilen der Datei benutzt und dabei aber jedesmal nach Logindaten fragt. Shell root@linux:/home/bsyll001# for x in ‘cat ~/machines.txt‘; do rsync -plarv /etc/mpd.conf root@$x:/etc/; done

8

Haupt-Daemon starten Der Daemon des Hauptrechners muss als Root gestartet werden. Ob das geklappt hat und welche Rechner dem so genannten MPD-Ring angeschlossen sind, sieht man mit ’mpdtrace’. Shell bsyll001@linux:~$ sudo su root@linux:/home/bsyll001# mpd --daemon root@linux:/home/bsyll001# mpdtrace -l linux_35720 (192.168.1.8)

An der Zeichenkette ’linux_35720’ erkennt man, dass der Host ’linux’ heißt und sein Port ’35720’ ist. Diese Angaben sind wichtig, um Nebenrechner mit einem Daemon wie diesem zu verbinden. Mit ’mpdallexit’ lassen sich alle gestarteten Daemons beenden. Ansonsten laufen sie im Hintergrund des Linux-Systems, auch wenn die Shell geschlossen wird. Nach einem Neustart des Hauptrechners muss der Haupt-Daemon auch wieder erneut gestartet werden. Nebenrechner mit dem Haupt-Daemon verbinden Jeder Nebenrechner der an einen MPD-Ring gebunden werden soll, muss mit dessen Daemon verbunden werden. Dadurch stellt er seine CPUs zur Verfügung. Shell skynet@cyberdyne:~$ mpd --daemon --host=linux --port=35720 --ncpus=8

Nach einem Neustart eines der Nebenrechner muss dessen Verbindung zum Haupt-Daemon auch wieder erneut gestartet werden.

9

Kapitel 4

Befehlssatz der API 4.1

Top 7 Funktionen

Obwohl die MPI-API ca. 125 Funktionen umfasst, benutzen selbst größere MPI-Anwendungen nicht mehr als 25 davon. Die API ist für viele, eben auch konkurrierende, Konzepte paralleler Programmierung entworfen worden. Das einfachste Konzept ist die so genannte blockierende Punkt-Zu-Punkt-Kommunikation für Prozesse. Nachfolgend werden tabellarisch sieben ausgewählte Funktionen kurz erläutert und anschließend in einem Hello-World-Programm in Aktion näher vorgestellt.

F UNKTION MPI_Init MPI_Finalize MPI_Comm_rank MPI_Comm_size MPI_Get_processor_name MPI_Send MPI_Recv

A UFGABE Initialisiert MPI-Statusmaschine. Immer zuerst auszuführen. Beendet MPI-Statusmaschine. Immer zuletzt auszuführen. Gibt die ID des Prozesses zurück (0=Rootprozess). Gibt die Anzahl aller Prozesse bzw. IDs zurück. Gibt den Rechnernamen des Prozesses zurück. Sendet Daten an bestimmten Prozess. Empfängt Daten von einem bestimmten Prozess.

Tabelle 4.1: Grundlegende MPI-Funktionen

4.2

Hello, world!

Ein kurzes Programm mit Brian W. Kernighans Teststring ’Hello, world!’ soll die Einfachheit der MPI-API demonstrieren. Nacheinander kommen hier die bisher vorgestellten Funktionen von MPI zum Einsatz. MPI verhält sich dabei in einer MPI-Anwendung wie eine Statusmaschine, deren Zustände mit Funktionen der MPI-API gesetzt, geändert und abgefragt werden können. Da es sich bei MPI-Anwendungen in aller Regel um verteilte Anwendungen handeln sollte, muss man bei der Programmierung mit dieser Statusmaschine zusätzlich bedenken, in welchem Prozess, unter welchen Bedingungen gerade welches Stück Code ausgeführt werden soll.

10

Listing 4.1: VER TEILTES H ELLO , WORLD ! 1

#include

2

#include

3 4 5

int main(int argc, char **argv) {

6

int rank, size;

// eigene Prozess-ID und Anzahl aller

7

char name[80];

// Name eines Haupt- oder Neben-Rechners

8

int name_length;

// Laenge des Namens

9

MPI_Status status;

// Status einer erhaltenen Nachricht

int i;

// eine Laufvariable

10 11 12

// MPI starten

13

MPI_Init(&argc, &argv);

14

// eigene Prozess-ID ermitteln

15

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

16

// Anzahl aller Prozess-IDs ermitteln

17

MPI_Comm_size(MPI_COMM_WORLD,&size);

18

// Name des Haupt- oder Neben-Rechners ermitteln

19

MPI_Get_processor_name(name,&name_length);

20 21

// wenn Haupt-Prozess

22

if ( rank == 0 ) {

23

// Infos des Haupt-Prozesses ausgeben

24

printf("Hello, world!\n");

25

printf("Haupt-Prozess: id=%d von %d IDs auf HPC=%s\n",i,size,name);

26

// fuer jeden Neben-Prozess

27

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

28

// empfange Name des Neben-Rechners

29

MPI_Recv(name,80,MPI_CHAR,i,999,MPI_COMM_WORLD,&status);

30

// Infos des Neben-Prozesses ausgeben

31

printf("Neben-Prozess: id=%d von %d IDs auf HPC=%s\n",i,size,name);

32

}

33

} // sonst einer der Neben-Prozesse

34

else {

35

// sende Name des Neben-Rechners an Haupt-Prozess

36

MPI_Send(name,80,MPI_CHAR,0,999,MPI_COMM_WORLD);

37

}

38 39

// MPI beenden

40

MPI_Finalize();

41 42

4.3

return 0; }

Kompilierung

Die Python-Scripte von MPICH2 zum Kompilieren von MPI-Anwendungen nutzen die Compiler der GNU Compiler Collection. Damit sind auch alle Argumente wie ’-Wall’, CPU-Architektur11

Argumente oder auch Argumente zur Optimierung nutzbar. Shell bsyll001@linux:~$ mpicc -Wall -o hello hello.c bsyll001@linux:~$ ls -l ./hello -rwxr-xr-x 1 bsyll001 bsyll001 11435 2010-01-18 15:56 ./hello bsyll001@linux:~$ mpicc -Wall -O3 -march=pentium4 -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops -o hello hello.c bsyll001@linux:~$ ls -l ./hello -rwxr-xr-x 1 bsyll001 bsyll001 13467 2010-01-18 15:56 ./hello bsyll001@linux:~$ strip --strip-all ./hello bsyll001@linux:~$ ls -l ./hello -rwxr-xr-x 1 bsyll001 bsyll001 5560 2010-01-18 15:56 ./hello

4.4

Ausführung

Ein Prozess Eine MPI-Anwendung ist wie gewohnt direkt in der Shell ausführbar. Es wird aber nur ein Prozess gestartet. Selbst wenn die CPU mehrere Kerne hat, wird nur einer genutzt, denn eine MPI-Anwendung ist keine Multi-Thread-Anwendung, sondern eine Multi-Prozess-Anwendung. Um zusätzlich die Multi-Threading-Fähigkeiten von CPUs nutzen zu können, müsste eine MPIAnwendung z.B. um Funktionen von OpenMP erweitert werden. Shell bsyll001@linux:~$ ./hello Hello, world! Haupt-Prozess: id=0 von 1 IDs auf HPC=linux

Mehrere Prozesse Da es sich heutzutage in aller Regel bei CPUs um Multi-Task-Prozessoren handelt, sind mehrere quasi parallele Prozesse auf der gleichen Maschine möglich. Auch wenn das bei Single-CoreCPUs keinen Geschwindigkeitsvorteil bringt. Es sei denn, das Betriebssystem verteilt die Prozesse auf mehrere Kerne einer eventuell vorhandenen Multi-Core-CPU. Im HPC-Bereich kommt der Geschwindigkeitsvorteil mit MPI erst in einem MPD-Ring aus mehreren CPUs von eventuell mehreren Maschinen zur Geltung. Shell bsyll001@linux:~$ sudo mpd --daemon bsyll001@linux:~$ sudo mpdtrace -l linux_39530 (127.0.0.1) bsyll001@linux:~$ sudo mpiexec -np 3 ./hello Hello, world! Haupt-Prozess: id=0 von 3 IDs auf HPC=linux Neben-Prozess: id=1 von 3 IDs auf HPC=linux Neben-Prozess: id=2 von 3 IDs auf HPC=linux

12

Kapitel 5

MPI-Beispiel - Integralrechnung Die einfachste Methode ein Integral in einem bestimmten Intervall zu berechnen, ist die Trapezmethode. Dabei wird die Fläche unterhalb einer Funktion in eine bestimmte Anzahl von Trapezen unterteilt und deren Flächen zum Schluss summiert. Da die Trapeze voneinander unabhängig sind, eignet sich diese Approximation eines Integrals hervorragend für eine parallele Berechnung mit einer MPI-Anwendung. In der Anwendung ist das Intervall [a = 0; b = 1] genau wie die Funktion f (x) = x hart kodiert, zu der die Stammfunktion F (x) = 12 x2 lautet. Mit Stammfunktionen lässt sich ein Integral leicht Rb durch a f (x) dx = F (b) − F (a) berechnen.

Z

1

x dx = 0

1 1 2 1 2 (1) − (0) = 2 2 2

(5.1)

Für die Approximation mit der Trapezmethode ergibt sich folgende allgemeine Formel. Dabei entspricht n in der Formel der Anzahl der Trapeze bzw. der Variablen size als Anzahl der Prozesse der MPI-Anwendung. Die Variable h entspricht in der Anwendung width für die Breite der Trapeze.

Z

b

f (x) dx ≈ a

1 1 1 h[f (x0 ) + f (x1 )] + h[f (x1 ) + f (x2 )] + ... + h[f (xn−1 ) + f (xn )] 2 2 2

Abbildung 5.1: Die Funktion f(x)=x

13

(5.2)

Listing 5.1: I NTEGRALRECHNUNG MIT DER T RAPEZMETHODE 1

#include

2

#include

3 4

// hart kodierte Funktion f(x) = x

5

float f(float x) {return x;}

6 7

// Flaeche eines Trapezes

8

float calculation(float local_a, float local_b, float width)

9

{

10 11

return (f(local_a) + f(local_b)) / 2.0 * width; }

12 13 14

int main(int argc, char **argv) {

15

int rank, size;

// eigene Prozess-ID und Anzahl aller

16

float a = 0.0, b = 1.0;

// Intervall des Integrals

17

float width, local_a, local_b;

// Breite, linke+rechte Seite eines Trapezes

18

float trapez, integral = 0;

// Trapeze und Summe davon

19

MPI_Status status;

// Status einer erhaltenen Nachricht

20

int i;

// eine Laufvariable

21 22

// MPI starten

23

MPI_Init(&argc, &argv);

24

// eigene Prozess-ID ermitteln

25

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

26

// Anzahl aller Prozess-IDs ermitteln

27

MPI_Comm_size(MPI_COMM_WORLD,&size);

28 29

// Breite, linke+rechte Seite eines Trapezes

30

// sind fuer jeden Prozess zu berechnen

31

width = (b-a) / size;

32

local_a = a + rank * width; local_b = local_a + width;

33 34 35

// Trapez durch jeweiligen Prozess berechnen

36

trapez = calculation(local_a, local_b, width);

37 38

// wenn Haupt-Prozess

39

if ( rank == 0 ) {

40

integral = trapez;

41

// fuer jeden Neben-Prozess

42

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

43

// empfange Trapez des Neben-Prozesses

44

MPI_Recv(&trapez,1,MPI_FLOAT,i,999,MPI_COMM_WORLD,&status);

45

integral += trapez;

46

}

47

printf("Integral mit %d Trapez%s im Intervall [%f;%f] ist %f\n"

48

,size,(size==1)?"":"en",a,b,integral);

14

49

} // sonst einer der Neben-Prozesse

50

else {

51

// sende Trapez des Neben-Prozesses an Haupt-Prozess

52

MPI_Send(&trapez,1,MPI_FLOAT,0,999,MPI_COMM_WORLD);

53

}

54 55

// MPI beenden

56

MPI_Finalize();

57

return 0;

58

}

Die Anwendung gibt den erwarteten Wert 0.5 für die Fläche unterhalb der simplen Funktion f (x) = x im Intervall [0; 1] zurück. Wenn man die Anzahl der zu startenden Prozesse auf einen höheren Wert setzt als ein MPD-Ring zur Verfügung stellt, dann bremst das eine MPIAnwendung aus. Diese Tatsache führt bei einem Anwender eines MPD-Rings noch nicht zu einem Problem, da ihm die Anzahl der CPUs bekannt sein dürfte. Sollen mehrere Anwender einen MPD-Ring nutzen, dann entsteht allerdings ein Verteilungsproblem. Shell bsyll001@linux:~$ mpicc -Wall -o intpar intpar.c bsyll001@linux:~$ ./intpar Integral mit 1 Trapez im Intervall [0.000000;1.000000] ist 0.500000 bsyll001@linux:~$ sudo mpiexec -np 1 ./intpar Integral mit 1 Trapez im Intervall [0.000000;1.000000] ist 0.500000 bsyll001@linux:~$ sudo mpiexec -np 32 ./intpar Integral mit 32 Trapezen im Intervall [0.000000;1.000000] ist 0.500000

Es ist kein Zufall, dass ein einziges Trapez ausreicht, um bei der Funktion f (x) = x auf den richtigen Wert 0.5 oder beispielsweise im Interval [0; 2] auf den Wert 2.0 zu kommen. Denn die Fläche unter dieser Beispielfunktion ist selbst immer ein Trapez. Bei nichtlinearen Funktonen bräuchte man sicher deutlich mehr Trapeze, um sich dem exakten Wert anzunähern.

15

Anhang A

Verzeichnisse A.1

Literaturverzeichnis [PP97] Pacheco, Peter S.: Parallel Programming with MPI 1. Edition, Morgan Kaufmann, 1997. [MQ03] Quinn, Michael J.: Parallel Programming in C with MPI and OpenMP 1. International Edition, Mc Graw Hill, 2003.

A.2

Internetquellen

• Admin-Informationen für MPICH2 - http://debianclusters.cs.uni.edu/index.php/ MPICH:_Parallel_Programming • Flynn’sche Taxonomie - http://en.wikipedia.org/wiki/Flynn’s_taxonomy • Funktion f (x) = x - http://www.wolframalpha.com/input/?i=plot+x+from+0+to+1 • Installer’s Guide für MPICH2 - http://www.mcs.anl.gov/research/projects/mpich2/ documentation/files/mpich2-1.2.1-installguide.pdf • User’s Guide für MPICH2 - http://www.mcs.anl.gov/research/projects/mpich2/ documentation/files/mpich2-1.2.1-userguide.pdf

16