Für die Implementierung von PORTAL in FLOW wurde PORTAL optimiert. Socket-Schnittstellen sind Schnittstellen zwischen zwei Prozessen. Die Schnittstellen sind nicht genormt, stellen aber einen Industriestandard dar. Dies liegt wahrscheinlich an der leichten Verständlichkeit und der guten Einfügung der Sockets in die UNIX-Umgebung [Santifaller, 1990]. Es sind zwei Arten von Sockets zu unterscheiden: Internet-Sockets und UNIX-Domain-Sockets.
Ein Internet-Socket ermöglicht den Austausch von Daten zwischen zwei Programmen auf zwei Rechnern, die über das Internet verbunden sind. Die Geschwindigkeit der Kommunikation zweier Prozesse über einen Internet-Socket hängt stark von der Vernetzung ab. Sie ist einerseits bedingt durch die Art des verwendeten Netzwerkes, andererseits durch andere Kommunikationen im Netz. Die Anbindung des Parsytek Power X'plorers an das Internet ist besonders ungünstig, da dieser nur über eine Workstation indirekt erreichbar ist. Deshalb erreicht das Programm PORTAL über einen Internet-Socket vom Power X'plorer aus eine Übertragungsleistung von etwa 20 bis 30 Kilobyte pro Sekunde. Sie ist somit weit von der theoretischen Übertragungsleistung der Links des Parallelrechners und der möglichen Übertragungsleistung des Internets entfernt.
Aufgrund der genannten Gründe wurde die Kommunikation auf einen UNIX-Domain-Socket umgestellt. Ein UNIX-Domain-Socket kann die Daten nur lokal übertragen. Die Übertragungsleistung eines solchen Sockets ist wesentlich höher als die eines Internet-Sockets. Des weiteren besteht kein Unterschied zwischen beiden Sockets.
Die Übertragungsleistung vom Parallelrechner zur Workstation konnte so auf bis zu 400 Kilobyte pro Sekunde gesteigert werden. Hierdurch wurde die Zeit für den Datenaustausch auf ein Zwanzigstel verringert.
Die Initialisierung des Sockets mußte deshalb auf der Seite des sendenden Prozesses sowie auf der Seite des empfangenden Prozesses überarbeitet werden. Der empfangende Prozeß initialisiert nun den Socket mit dem Unterprogramm init_socket_read :
void init_socket_read(int *sock, char *pathname) { char output[256]; struct sockaddr server; /* Erstellen eines Unix-Sockets */ *sock = socket(AF_UNIX, SOCK_STREAM, 0); if (*sock < 0) { perror("opening stream socket"); exit(1); } server.sa_family = AF_UNIX; strcpy(server.sa_data, pathname); unlink(pathname); /* Zuweisen des Namens */ if (bind(*sock, (struct sockaddr *) & server, sizeof(struct sockaddr)) < 0) { perror("socket_bind"); exit(1); } if (listen(*sock, 5) < 0) { perror("listen"); exit(1); } sock_dputs("listen succeeded"); sock_dputs(output); return; }
Auf der Seite des Senders mußte das Unterprogramm init_socket_write geändert werden:
void init_socket_write(int *sock, char *pathname) { struct sockaddr server; /* Erstellen eines Unix-Sockets */ *sock = socket(AF_UNIX, SOCK_STREAM, 0); server.sa_family = AF_UNIX; strcpy(server.sa_data, pathname); /* Initialisieren der Verbindung */ if (connect(*sock, (struct sockaddr *) & server, 110) < 0) { perror("connecting stream socket"); exit(1); } return; }
Die maximale Übertragungsrate bei der Datenübertragung über einen UNIX-Socket erreicht man beim Parsytek Power X'plorer, wenn die Größe der einzelnen Datenpakete in einem Bereich von maximal 8 Kilobyte liegt. Das Festlegen der Datenpaketgröße wird vom Sender vorgenommen. Das hierfür verwendete Unterprogramm ist send_data. In der Originalversion von PORTAL wurde das Verschicken mit Hilfe der Socket-Kommunikationsroutine writev durchgeführt. writev verschickt eine Strukur vom Typ iovec. Diese ist wie folgt definiert:
struct iovec { caddr_t iov_base; /* Anfangsadresse der Daten */ int iov_len; /* Blocklaenge */ }Zuerst wird hierbei die Größe (iov_len) des zur Übertragung anstehenden Datenpaketes an den Empfänger geschickt. Danach werden die Daten selbst in einem Stück gesendet. Eine Geometrie, die als UCD in AVS dargestellt werden soll, kann bei der Übertragung leicht eine Größe von mehr als 100 Kilobyte erreichen. Wenn nun ein Datenpaket dieser Größe auf einmal gesendet wird, erreicht man nur eine sehr geringe Transferrate.
/* Zeiger auf Anfang des Datenfeldes setzen */ ptr = (char *) data->data; /* Festlegen der Blocklaenge des aktuellen Blocks */ aktueller_block = blocklaenge; n_left = data->length; if (n_left < blocklaenge) aktueller_block = n_left; while ((n_left > 0)) { n_write = write(sock, ptr, aktueller_block); /* Senden der Daten */ if (n_write > 0) { /* Zeiger auf naechsten Block setzen, aktuelle Blocklaenge bestimmen */ n_left = n_left - n_write; ptr = ptr + n_write; if (n_left < blocklaenge) aktueller_block = n_left; } else if (n_write == 0) fail--; }
Durch die beschriebenen Änderungen konnte die Übertragungszeit für eine zu visualisierende Geometrie stark reduziert werden. Für einen Beispieldatensatz mit 3411 Knoten und 6500 Elementen verringerte sich durch die Optimierungen die Übertragungszeit von etwa 12 Sekunden auf nur noch etwa eine halbe Sekunde. Die Darstellung bremst jetzt den Rechenprozeß nur noch gering. Die Verlängerung der Gesamtrechenzeit durch die Darstellung ist auf ein vertretbares Maß reduziert worden.