Referat: Programmieren in CNAPS-C von Peter Wendzioch CNAPS-Projekt Sommersemester 1998 Hochschule Bremen 13.05.2016 Anzahl der Seiten: 23 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 THEMENÜBERSICHT 1. EINLEITUNG 3 2. DIE PROGRAMMSTRUKTUR 4 3. DOMÄNEN UND PARALLELITÄT 5 3.1 3.2 3.3 3.4 3.5 3.6 3.7 ORGANISATION DER DATEN DER DATENTYP DOMAIN POLY- UND MONO-DATENTYPEN PARALLELER CODE ABLAUFSTEUERUNG IN PARALLELEM CODE VERSCHACHTELTE DOMAIN EXECUTION STATEMENTS NAMENSRÄUME (NAME SPACES) 6 7 8 9 10 11 12 4. DATENTYPEN, ZEIGER, OPERATOREN 13 4.1 4.2 4.3 4.4 4.5 4.6 13 14 15 16 17 18 GRÖßE VON DATENTYPEN SCALED – SKALIERBARE FIXPUNKTDATENTYPEN ZEIGER DEKLARATION VON ZEIGERN EINIGE NEUE OPERATOREN NEUE BEDEUTUNG EINIGER OPERATOREN MIT POLY-VARIABLEN 5. FILE I/O 19 5.1 5.2 19 20 DIE BIBLIOTHEK CNIO.H ZUSAMMENFASSUNG DER FILE I/O-OPERATIONEN 6. DIE ASM DEKLARATION 21 7. RESTRIKTIONEN CNAPS-C VS. ANSI-C 22 8. LISTING OF MATMUL.CN 23 Referat: Programmieren in CNAPS-C Seite: 2 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 1. Einleitung CNAPS-C ist die Hochsprache, mit der Algorithmen auf dem CNAPS-Board implementiert werden. Sie werden mit dem CNAPS-Compiler cnc kompiliert und durch CNapi-Aufrufe vom Hostrechner auf das CNAPS-Board übertragen und dort ausgeführt. Eine andere Möglichkeit, Programme für das CNAPS-Board zu entwickeln, bietet die Assemblersprache CPL. CPL setzt jedoch wie alle maschinennahen Sprachen sehr gute Kenntnisse der Hardware voraus und wird hier nicht näher erläutert. Weitere Informationen zu CNAPS-C und CPL findet man in den Manuals CNAPS-C Programming Guide CNAPS-C Language Reference CPL Programming Guide QuickLib Libraries Reference Manual Einige Begriffsdefinitionen: CNAPS SIMD domain CSC PN CNapi CPL Connected Network of Adaptive ProzessorS Single Instruction Multiple Data Datentyp/-struktur für Parallelverarbeitung CNAPS Sequencer Chip Prozessor Node CNAPS Application Programming Interface CNAPS Programming Languange Referat: Programmieren in CNAPS-C Seite: 3 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 2. Die Programmstruktur Programme in CNAPS-C sind grundsätzlich wie ANSI-C Programme aufgebaut, mit zwei wichtigen Ausnahmen: In CNAPS-C ist das Konzept einer main-Funktion, die den Startpunkt eines Programms definiert, nicht implementiert. Eine Funktion kann zwar den Namen „main“ haben, sie hat allerdings keine besondere Bedeutung. Statt dessen können Funktionen als entry points definiert werden. Ein CNAPS-C Programm wird durch Aufrufen einer dieser entry points gestartet, weshalb mindestens eine Funktion als entry point definiert sein muß. entry void IrgendeinName(void) { } Da es kein Konzept einer main-Funktion gibt, entfällt auch der Mechanismus der Parameterübergabe durch argc und argv[]. Deshalb können auch Variablen als entry points definiert werden und somit zur Parameterübergabe an einen Algorithmus verwendet werden: entry const int Anfangswert = 100; Durch das Schlüsselwort const wird nur vermieden, daß die Variable zur Laufzeit geändert werden kann. Die Variable Anfangswert kann jedoch durch einen CNapi-Aufrufe geändert werden. Die Zuweisung des Wertes 100 wird als Defaultwert benutzt. Referat: Programmieren in CNAPS-C Seite: 4 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3. Domänen und Parallelität Domänen stellen dem Programmierer den Mechanismus zur Verfügung, in dem die Fähigkeit zur Parallelverarbeitung implementiert ist. Domänen sind vergleichbar mit dem C-Datentyp struct, mit der Besonderheit, daß in einer Domäne eine logische Gruppe von Prozessoren zusammengefaßt wird, mit denen eine Parallelverarbeitung durchgeführt wird. Eine Domäne kann Mitgliedsvariablen und -funktionen beinhalten. Instanzen sind die konkreten Ausprägungen einer Domäne. Instanzen sind vergleichbar mit den Objekten einer C++ Klasse. Eine Domäne kann mehrere Instanzen haben, die jeweils mit einer Gruppe von Prozessoren assoziiert sind. Dennoch unterscheiden Domänen sich von C++ Klassen in folgenden Punkten: Domänen haben keinen Mechanismus zur Vererbung. Mitgliedsvariablen und –funktionen können nicht als private deklariert werden. Sie sind immer public. Alle Mitgliedsvariablen und –funktionen einer Domäne können parallel verarbeitet bzw. ausgeführt werden. Prozessoren können nicht dynamisch zugewiesen werden. Referat: Programmieren in CNAPS-C Seite: 5 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.1 Organisation der Daten Um den Vorteil der Parallelverarbeitung nutzen zu können, müssen die Daten vor der Verarbeitung organisiert werden. Organisation bedeutet dabei die "geschickte" Einteilung der Daten in Stränge, die parallel von einer Gruppe von Prozessoren verarbeitet werden können. Verdeutlicht werden soll dies am Beispiel einer Multiplikation einer 3x3 Matrix mit einem 3-spaltigen Vektor: Referat: Programmieren in CNAPS-C Seite: 6 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.2 Der Datentyp domain Eine Domäne wird mit dem Schlüsselwort domain deklariert. Die Deklaration muß mit einem Semikolon abgeschlossen werden. Bei der Deklaration von Domänen muß darauf geachtet werden, daß die Anzahl der zugewiesenen PNs nicht die Anzahl der physikalisch vorhandenen PNs übersteigt. Syntax 1: domain DOMAINNAME { // Deklaration der Mitgliedsvariablen } INSTANZNAME[KONSTANTE_ANZAHL_PN]; Syntax 2: domain DOMAINNAME { // Deklaration der Mitgliedsvariablen }; domain DOMAINNAME INSTANZNAME[KONSTANTE_ANZAHL_PN]; Referat: Programmieren in CNAPS-C Seite: 7 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.3 poly- und mono-Datentypen Die Schlüsselwörter mono und poly sind sogenannte "qualifier", die angeben, ob ein Datentyp in einer Domäne nur einmal für alle Prozessoren existiert, oder ob jeder Prozessor mit seiner eigenen Kopie dieser Variablen arbeitet. Außerhalb von parallelem Code gibt es nur mono-Datentypen und innerhalb parallelen Codes sind die Datentypen defaultmäßig poly. Einfache Zählvariablen sollten daher mit mono deklariert werden. Referat: Programmieren in CNAPS-C Seite: 8 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.4 Paralleler Code CNAPS-C Programme sind immer eine Mischung aus seriellem und parallelem Code. Nur ganz bestimmte Teile eines CNAPS-C Programms werden parallel ausgeführt. In CNAPS-C gibt es zwei verschiedene Möglichkeiten, eine Parallelverarbeitung zu implementieren. Syntax 1 - Paralleler Code in Mitgliedsfunktion implementiert: Deklaration void DOMAINNAME::FUNKTIONSNAME(PARAMETER) { // Parallel auszuführenden Code hier einfügen. } Aufruf [domain DOMAINNAME].FUNKTIONSNAME(); Syntax 2 - Paralleler Code in serieller Funktion implementiert: Deklaration void serielle_funktion(void) { // Hier steht nur serieller Code. [domain DOMAINNAME].{ // Parallelen Code hier einfügen. } // Hier steht wieder nur serieller Code. } Aufruf serielle_funktion(); Referat: Programmieren in CNAPS-C Seite: 9 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.5 Ablaufsteuerung in parallelem Code Innerhalb von domain execution statements können natürlich auch Befehle wie if, while, do und for eingesetzt werden. Beziehen sich diese Befehle nur auf mono-Variablen, so ist die Ablaufsteuerung für alle PNs gleich. Unter Berücksichtigung von poly-Variablen, werden beispielsweise die PNs, deren poly-Variable einen if-test nicht bestehen, inaktiv und warten mit dem Programmablauf, bis die aktiven Prozessoren ihren if-Block beendet haben. Ein Beispiel soll dies verdeutlichen: domain Beispiel { mono i; poly Wert; } Proz[10] [domain Beispiel].{ if (i == 0) { // Wenn i=0 (mono) ist, dann führen // alle PNs (Proz[0..9]) diesen Block aus. } else { // Ansonsten führen alle PNs diesen // Block aus. } if (Wert <= 100) { // Nur die PNs der Variable Wert<=100 // (poly) ist führen diesen Block aus. // Alle anderen PNs dieser Domäne sind // inaktiv und warten. } } Referat: Programmieren in CNAPS-C Seite: 10 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.6 Verschachtelte domain execution statements Ein domain execution statement kann auch in bereits-parallelem Code auftauchen. Die Auswirkungen zeigt das folgende Beispiel: domain Beipiel { mono i; poly WertA; poly WertB; } Proz[10]; [ domain Beispiel ].{ if (WertA < 10) { // Hier sind nur die PNs aktiv, deren // Variable WertA kleiner als 10 ist. [domain Beispiel].{ // Hier sind aber alle wieder aktiv. WertB = 5; } } } Referat: Programmieren in CNAPS-C Seite: 11 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 3.7 Namensräume (name spaces) Jede Domäne hat einen eigenen Namensraum für ihre Bezeichner. Dadurch können in verschiedenen Domänen Variablen mit gleichem Namen existieren. Auch die "mono"-Domäne hat einen eigenen Namensraum: int abc = 1; int xyz = 2; // Beides mono-Typen domain Eins { mono int abc; poly int ijk; } EinsProz[10]; domain Zwei { mono int abc; poly int rst; } ZweiProz[10]; [ domain Eins ].{ abc = 1; // abc von Domäne Eins Zwei::abc = 2; // abc von Domäne Zwei void::abc = 3; // globales abc der mono-Domäne EinsProz[3].ijk = 10; // ijk von PN3 } Referat: Programmieren in CNAPS-C Seite: 12 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4. Datentypen, Zeiger, Operatoren 4.1 Größe von Datentypen Datentyp Größe int, short 16 bit char 8 bit long 32 bit float, double nicht verfügbar scaled 8 oder 16 bit zeiger auf poly-Objekt 16 bit zeiger auf mono-Objekt 32 bit zeiger auf ein domain-Objekt 16 bit Referat: Programmieren in CNAPS-C Seite: 13 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4.2 scaled – Skalierbare Fixpunktdatentypen Mit dem Schlüsselwort scaled kann man Fixpunkt-Datentypen definieren. Dabei werden die Bits für den Ganzahl- und den Nachkommateil angegeben. typedef scaled 4 12 fpvar; Was man in dieser Definition noch nicht sehen kann, ist die Tatsache, daß der Datentyp noch drei weitere Standardeigenschaften hat: signed / unsigned Der Datentyp ist "signed" Standardmäßig sind alle numerischen Datentypen vorzeichenbehaftet. jammed / unjammed Der Datentyp ist "unjammed" Verliert ein jammed-Datentype niederwertige Bits z.B. durch shiften, casten oder Multiplikation, so wird der Wert der Variablen auf den "ungeraden" Wert gesetzt, der dem eigentlichen Ergebnis am nächsten kommt. Mit ungerade ist gemeint, daß das niederwertigste Bit auf 1 gesetzt ist. saturated / unsaturated Der Datentyp ist "unsaturated" Tritt bei einer Operation ein Überlauf bzw. Unterlauf auf, so ist der Wert der Variablen undefiniert. Mit dem Schlüsselwort saturated wird ein Datentyp angewiesen, den größt- bzw. kleinstmöglichen darstellbaren Wert anzunehmen. Eine Mögliche Deklaration wäre auch typedef scaled 8 8 unsigned saturated jammed fpvar2; Referat: Programmieren in CNAPS-C Seite: 14 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4.3 Zeiger Durch die CNAPS-C-Erweiterungen hinsichtlich der Parallelverarbeitung ergeben sich 4 verschiedene Arten von Zeigern: Referat: Programmieren in CNAPS-C Seite: 15 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4.4 Deklaration von Zeigern domain abc { poly int z; } Proz[3]; [domain abc].{ mono int i; mono int array[3]; mono poly mono poly int int int int *mono *mono *poly *poly monoPtrToMonoInt; monoPtrToPolyInt; polyPtrToMonoInt; polyPtrToPolyInt; monoPtrToMonoInt monoPtrToPolyInt polyPtrToMonoInt polyPtrToPolyInt = = = = &i; &z; &array[1]; &z; } Referat: Programmieren in CNAPS-C Seite: 16 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4.5 Einige neue Operatoren >? Ermittelt den Maximalwert zweier Operanden <? Ermittelt den Minimalwert zweier Operanden >?= Weist den Maximalwert einer poly-Variablen einer mono-Variablen zu <?= Weist den Minimalwert einer poly-Variablen einer mono-Variablen zu. ,= Weist einen zufällig ausgewählten Wert einer poly-Variablen einer monoVariablen zu. (Wird verwendet, wenn es egal ist, welcher Prozessor diesen Wert enthält, z.B. weil man weiß, daß nur 1 Prozessor aktiv ist.) Beispiel: domain abc { mono int max_Wert; poly int poly_Wert; } Proz[10]; [domain abc].{ // Irgendwelche Berechnungen auf poly_Wert. . . . // Absolutbetrag von poly_Wert. max_Wert >?= (poly_Wert >? –poly_Wert); }; Referat: Programmieren in CNAPS-C Seite: 17 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 4.6 Neue Bedeutung einiger Operatoren mit poly-Variablen x ist eine poly-Variable, y ist eine mono-Variable y += x Summiert die Werte von x aller aktiven PNs. y -= x Summiert die negierten Werte x aller aktiven PNs. y *= x Multipliziert die Werte x der aktiven PNs. y &= x Bitweises UND aller Werte x der aktiven PNs. y |= x Bitweises ODER aller Werte x der aktiven PNs. y ^= x Bitweises XOR aller Werte x der aktiven PNs. Referat: Programmieren in CNAPS-C Seite: 18 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 5. File I/O 5.1 Die Bibliothek cnio.h Die Daten die von einem CNAPS-C Algorithmus bearbeitet werden sollen müssen in Eingabedateien bereitgestellt werden. Die Ergebnisse werden dann nach der Verarbeitung in Ausgabedateien geschrieben. Die Unterstützung für die Ein- und Ausgabe von Daten bietet die Bibliothek cnio.h, die in jedem CNAPS-C Programm eingebunden sein sollte. Für einen Dateizugriff muß zunächst eine Datei mit dem FILE()-Befehl deklariert werden: Mit den Befehlen open() und connect() muß die Datei geöffnet und mit der physikalischen Datei im Filememory verbunden werden, bevor man Leseoder Schreiboperationen ausführen kann. Es gilt, daß zwar mehrere Dateien mit open() geöffnet sein können, aber es kann immer nur eine Datei zum Lesen und eine zum Schreiben mit connect() verbunden sein: open (EINGABE_DATEI); open (AUSGABE_DATEI); connect (EINGABE_DATEI); connect (AUSGABE_DATEI); // Leseoperationen a = getchar(); // Schreiboperationen; putchar(a); close (EINGABE_DATEI); close (AUSGABE_DATEI); Referat: Programmieren in CNAPS-C Seite: 19 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 5.2 Zusammenfassung der File I/O-Operationen Operation Beschreibung close() Schließt eine geöffnete Datei. connect() Verknüpft eine Datei mit einem I/O-Kanal (1 Eingabe und 1 Ausgabe). FILE() Deklariert eine Datei. flush() Schreibt den Pufferinhalt in die Datei. getchar(), Liest binäre Eingabedaten. getnum(), getword() open() Öffnet eine Datei. putchar(), Schreibt Daten im Binärformat. putnum(), putword() rewind() Setzt den Datenzeiger auf den Anfang der Datei. Referat: Programmieren in CNAPS-C Seite: 20 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 6. Die asm Deklaration Mit der asm Deklaration ist es möglich CPL-Code direkt in ein CNAPS-C Programm einzubinden. Innerhalb dieser Deklarationen darf nur CPL-Code verwendet werden, da diese Abschnitte von CNAPS-C Präprozessor ignoriert werden. asm [ register xxx = 5 ] { <<< // CPL-Code hier einfügen. >>> } Beispiel: entry void ptrIndirection(void) { char xl[10]; char *ptr = xl; /* This in-line assembly code does *ptr = 2 */ asm [ register plow,phigh = ptr; register tl; { <<< CTLdefault; LITERAL 0 lo; phigh rega shiftr4 LITERAL 7 inB and; logicA Areg t1; # t1 = phigh & 0x0700 plow regA shiftr8; # logic = plow >> 8 logicA AaddL t1 regB BaddRL; #add = pnid of mono ptr rpnid regA Alogiclatch addB xor; # logic = add ^ pnid omitx iflogic0; # xflag = (add == pnid) LITERAL 255 inA Alogiclatch plow regB and; LITERAL 255 lo logicA Areg tl; LITERAL 15 inA Alogiclatch phigh regB and; logicA AaddL t1 regB BaddRL; # add = offset addA Abase; # base = offset LITERAL 2 inA Amem cndx; # if (ptrPnid == pnid) # then *base = 2 >>> } ]; } Referat: Programmieren in CNAPS-C Seite: 21 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 7. Restriktionen CNAPS-C vs. ANSI-C Folgende Eigenschaften sind in einem CNAPS-C Programm nicht verfügbar bzw. eingeschränkt: Division (/) und Modulo (%) float- und double-Typen Zeiger auf Funktionen Bitfelder in structs und Unions Speicherallokation (z.B. malloc()). "main"-Funktion Programmgröße ist auf 64KB begrenzt Referat: Programmieren in CNAPS-C Seite: 22 Peter Wendzioch CNAPS-Projekt SS98 24.05.98 8. Listing of matmul.cn #define num_cols 3 #define num_rows 3 #define num_elem 3 #include <cnio.h> // DEFINITION DER DOMÄNE matrix_calc UND DER INSTANZ MAT[] domain matrix_calc { poly int matrix_row[num_cols]; poly int sum; }; domain matrix_calc MAT[num_rows]; // INITIALISIERUNG FILE I/O mono int i,j; mono int vector[num_elem]; FILE (MATFILE, inword, "*.dat", NULL, NULL); FILE (VECFILE, inword, "*.dat", NULL, NULL); FILE (RESFILE, outword,"*.dat", NULL, NULL); // LESEROUTINEN FÜR MATRIX UND VEKTOR void matrix_calc::readMatrix(int matrix_row[]) { mono int r, c; open (MATFILE); connect (MATFILE); for (r=O;r<num_rows;r++) { for (c=O;c<num_cols;c++) MAT[r].matrix_row[c] = getword(); } close (MATFILE); } void readVector(); { mono int v; open (VECFILE); connect (VECFILE); for (v=O;v<num_elem;v++) vector[v] = getword(); close (VECFILE); } // BERECHNUNG UND AUSGABE DER ERGEBNISSE entry void main(void) { mono int j; [domain matrix_calc].( readMatrix(matrix_row); readVector(); sum = 0; for (j=0; j<num_cols; j++) sum = sum + (matrix_row[j] * vector[j]); open (RESFILE); connect (RESFILE); for (j=0; j<num_rows; j++) { putword (MAT[j].sum); } } } Referat: Programmieren in CNAPS-C Seite: 23