Friedrich-Alexander-Universität UnivisSuche FAU-Logo
Techn. Fakultät Willkommen am Department Informatik FAU-Logo
Logo I4
Lehrstuhl für Informatik 4
Betriebssystemtechnik
 
  Vorlesung
    - UnivIS-Infos
    - Inhalt
    - Voraussetzungen
    - Prüfungen
    - Folien
 
  Übungen
    - Inhalt
    - Tipps
       * Teamarbeit mit svn
       * Tools
       * AOStuBS-System
    - Aufgaben
       * A 1
       * A 2
       * A 3
       * A 4
       * A 5
       * A 6
       * A 7
 
  Evaluation
Department Informatik  >  Informatik 4  >  Lehre  >  SS 2008  >  Betriebssystemtechnik  >  Übungen  >  Aufgabe 1

Aufgabe 1: OSE-I/O-Library

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?

Aufgabenbeschreibung

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

Ausgabetermin Vorgabe Abgabetermin
17.04.2008 OSE_Vorgabe1.tar.gz 24.04.2008, 14:00

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 Wanja 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 auch die Gruppenzusammensetzung mitteilen können.

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 gegebenenfalls 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.

Weiterhin 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 Exit-Code 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 der Lehrstuhl-Implementierung und den von eurer Implementierung nicht zu überschreitenden Wert (Angaben in Bytes). (Die Obergrenze entspricht dem Verbrauch der Lehrstuhl-Implementierung plus 5%.) Die statische Größe wird dabei mit dem Befehl size ermittelt. Der Stackverbrauch wird als Exit-Code zurückgegeben und kann somit nach Ausführung von der Shell ausgegeben werden (./test1; echo $?). Automatisiert ermittelt und addiert wird dies durch ein im Tar-Archiv mitgeliefertes Perl-Skript, welches durch make size ausgeführt werden kann.

Testprogramm Text Data BSS Stack Summe Eure Obergrenze
test1 559 0 12 152 723 759
test2 973 4 20 184 1181 1240
test3 1702 4 20 248 1974 2072

Diese Werte gelten für g++ (GCC) 4.2.3 (Debian 4.2.3-3), der im CIP-Pool der Standardcompiler ist.

Tipps

Um diese harten Anforderungen bezüglich 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 arbeiten (typedefs, die eine bestimmte Variante einer Klassenimplementierung wählen).
  • Mit #ifdefs innerhalb des Codes arbeiten.

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 disassembliertes Listing seiner Applikation.

  Impressum Stand: 2008-04-21 09:48   OS, WH