Friedrich-Alexander-Universität UnivisSuche FAU-Logo
Techn. Fakultät Willkommen am Department Informatik FAU-Logo
Logo I4
Lehrstuhl für Informatik 4
Betriebssystemtechnik
 
  Vorlesungsüberblick
  Voraussetzungen
  Vorlesungsfolien
  Übungen
  Tools
  Teamarbeit mit svn
  Schein, Prüfung
  Evaluation
Department Informatik  >  Informatik 4  >  Lehre  >  SS 2007  >  OSE  >  Übung

Betriebssystemtechnik (OSE) - SS 2007

Aufgabe 1: OSE-I/O-Library

In dieser Aufgabe soll eine im Speicherplatzverbrauch skalierbare Bibliothek zur formatierten Ausgabe von Zeichen, Zeichenketten, Ganzzahlen und Zeigern erstellt werden.

Ausgabetermin Vorgabe (spätester) Abgabetermin
19.04.07 OSE_Vorgabe1.tgz 26.04. 14:30

Lernziele

Ziel dieser Übung ist es, ein "Gefühl für Größe" zu bekommen. Wie gestaltet man eine Bibliothek so, dass sie in ihrer Codegröße mit der verwendeten Funktionalität skaliert? Was macht der Compiler aus meinem Code und wo kommen die vielen KBs eigentlich her?

Bearbeitung und Abgabe

Die Bearbeitung der Aufgabe soll wie angekündigt in einer Dreiergruppe erfolgen. Spätestens jetzt solltet ihr euch also eine Gruppe suchen. Die Abgabe der Aufgabe erfolgt bei Julio im Büro durch ein Mitglied der Gruppe. Wir werden uns dann per ssh im CIP Pool anmelden, wo eurer funktionstüchtiges Implement abgabereif liegen sollte. Dann müsst ihr mir auch die Gruppenzusammensetzung mitteilen.

Bitte beachtet die unten genannten Anforderungen an den Speicherplatzverbrauch!

Vorgabe

Die Vorgabe umfasst einen Verzeichnisbaum, in dem ihr eure Entwicklung durchführen könnt. Die Makefiles sind für die Anwendung auf den Debian/Linux PCs im CIP Pool gedacht. Wer zu Hause arbeiten will, muss sie ggfs anpassen.

Des weiteren umfasst die Vorgabe drei Testprogramme test1.cc bis test3.cc mit deren Hilfe ihr am Ende die Skalierbarkeit der Bibliothek nachweisen sollt.

Die einzige vorgegebene C++ Klasse ist OStreamDock. Sie hat eine Methode void out(char), die mit Hilfe des Systemaufrufs write() implementiert wird. Alle Aufgabefunktionen der zu erstellenden Bibliothek sollen darauf aufsetzen.

Des weiteren vorgegeben ist der Startup-Code, der u.a. für die Ausführung der Konstruktoren und Destruktoren aller globalen Objekte sorgt. Außerdem misst er den Stackverbrauch und gibt diesen als exitcode des Programms zurück.

Die Datei config.h wird in den g++-Optionen per forced include in jede Übersetzungseinheit eingebunden. Sie ist damit der ideale Ort für Konfigurierungs-Makros und ähnliches.

Funktionsumfang

Bei der "I/O-Library" sind lediglich Funktionen zur Ausgabe bereitzustellen. Eingabefunktionen sind nicht nötig. Außerdem werden auch Fließkommazahlen nicht unterstützt.

Wie man den drei Testprogrammen ansieht, sollen Anwendungsprogramme die Bibliothek mit Hilfe des Datentyps OutputStream aus "OutputStream.h" nutzen. Der Typ stellt die von cout her bekannten Ausgabeoperatoren operator << für Zeichen, Zeichenketten, Ganzzahlen und Zeiger zur Verfügung. Ob die Funktionen dieses Typs vielleicht aus Basisklassen geerbt werden oder mit Hilfe von Hilfsklassen implementiert werden, bleibt euch überlassen.

Neben den Ausgabeoperatoren, sollen folgende Methoden auf einem OutputStream-Objekt anwendbar sein:

void width (int) Setzt die Feldbreite für die nächste Ausgabe.
void fill (char) Setzt das Füllzeichen, das ausgegeben wird, wenn das Ausgabefeld aufgefüllt werden muss (Default: Leerzeichen)
void left () Ausgaben sollen ab sofort im Feld linksbündig erfolgen
void right () Ausgaben sollen ab sofort im Feld rechtsbündig erfolgen
void showbase (bool) Stellt ein, ob bei Integer-Zahlen die Basis ausgegeben wird ("0x" bei Basis 16, "0" bei Basis 8, "%" bei Basis 2)

Die Funktionen orientieren sich an der C++ Standardbibliothek. Neben den Ausgabeoperatoren und den hier genannten Funktionen sind die bekannten Manipulatoren hex, bin, dec oct und endl zu implementieren.

Speicherplatzverbrauch

Die folgende Tabelle zeigt den Speicherplatzverbrauch der drei Testprogramme in meiner Implementierung und den von eurer Implementierung nicht zu überschreitenden Wert (Angaben in Bytes). Die statische Größe wird dabei mit dem Befehl size ermittelt. Der Stackverbrauch wird als exitcode zurückgegeben und kann somit nach Ausführung von der Shell ausgegben werden (./test1 ; echo $?).

Testprogramm text data bss stack Summe Eure Obergrenze
test1 553 0 12 156 721 793
test2 956 4 20 188 1168 1284
test3 1667 4 20 252 1943 2137

Diese Werte gelten für g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21), der im CIP-Pool der Standardcompiler ist.

Tipps

Um diese harten Anforderungen bzgl. des Speicherplatzverbrauchs zu erfüllen, sind folgende Hinweise vielleicht hilfreich:

  • Virtuelle Funktionen sind zu vermeiden
  • Die Aufrufbeziehungen so ordnen, dass möglichst viel unbenutzte Funktionalität durch das "function-level linking" rausfällt.
  • Wo das "function-level linking" nicht reicht, kann man auch anwendungsspezifisch konfigurieren.
    • Mit konfigurierbaren Klassen (typedefs, die eine bestimmte Variante einer Klassenimplementierung wählen)
    • Mit #ifdefs innerhalb des Codes

Außerdem sollte man sich immer mal wieder ansehen, was Compiler und Linker eigentlich aus dem Programmcode machen. Dazu eignet sich der Befehl objdump. Mit objdump -D --demangle test1 erhält man z.B. ein relativ gut lesbares Diassembler-Listing seiner Applikation.

  Impressum   Datenschutz Stand: 2007-04-19 10:56   OS