Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ ep(7) — Reliant UNIX 5.44c4

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

crash(1M)

ep(7)                                                                 ep(7)

NAME
     ep - Event Profiler

BESCHREIBUNG
     Wenn man ein Programm schreibt, tritt häufig das Problem auf, daß ein
     Programmteil Ressourcen wie z. B. Speicherbereiche zuweist und diese
     gar nicht oder sogar mehrfach freigibt.

     Der Event Profiler ist ein Teil des Systemkerns, der es dem Entwickler
     ermöglicht, Informationen zu derartigen Ressourcen zu sammeln. Diese
     Ressourcen werden im folgenden als OBJEKTE bezeichnet. Beispiele für
     OBJEKTE sind Speicherbereiche, Locks, Datei-Deskriptoren oder belie-
     bige Dinge, die durch einen eindeutigen Schlüssel gekennzeichnet wer-
     den können.

     Während der Lebensdauer eines OBJEKTS können verschiedene Ereignisse
     eintreten. Standard-Ereignisse sind z. B. die Erzeugung und die Frei-
     gabe des OBJEKTS.

     Beispiel für ein OBJEKT ist ein Streams-Nachrichtenblock (msgb). Ein
     derartiges OBJEKT wird

     -  in den Funktionen allocb() oder dupb() erzeugt,

     -  in den Funktionen putq(), getq(), putbq() und putnext() verarbeitet
        und

     -  in der Funktion freeb() wieder freigegeben.

     Die Weitergabe einer Nachricht an ein weiteres Streams-Modul über
     putnext() kann beim Debuggen sehr interessant sein und sollte deshalb
     mitprotokolliert werden.

     Der Event Profiler muß von der Erzeugung, der Verwendung und der Frei-
     gabe der OBJEKTE informiert werden. Dazu gibt es drei verschiedene
     Arten von Ereignissen:

     -  Nach der Erzeugung eines neuen OBJEKTES muß dem Event Profiler mit-
        geteilt werden, daß ab jetzt Informationen zu diesem OBJEKT gesam-
        melt werden sollen. Das Erzeugungs-Ereignis wird dabei automatisch
        durch den Event Profiler für das OBJEKT gespeichert. Der Event Pro-
        filer speichert die Identifikation für den Tracepunkt - die soge-
        nannte Trace-ID -, einen Zeitstempel und die Aufrufverkettung,
        falls keine trace-spezifischen Daten beim Aufruf der Funktion über-
        geben wurden. In diesem Fall können z. B. zusätzlich zu der Aufruf-
        verkettung noch die Werte bestimmter Variablen mit abgespeichert
        werden. Mit diesen Informationen kann sehr leicht festgestellt wer-
        den, wer wann das OBJEKT erzeugt hat.







Seite 1                      Reliant UNIX 5.44               Gedruckt 11/98

ep(7)                                                                 ep(7)

     -  Außerdem können noch weitere Ereignisse in dem Profile des Event
        Profilers gespeichert werden. Diese Ereignisse sind Kontrollpunkte,
        an denen der Systemprogrammierer mitprotokollieren kann, wann und
        wo ein OBJEKT seinen Zustand oder seine Position geändert hat. Wie
        bei der Erzeugung des OBJEKTS können auch bei solchen Ereignissen
        trace-spezifische Informationen anstatt der Aufrufverkettung abge-
        speichert werden.

     -  Es muß dem Event Profiler mitgeteilt werden, wenn das OBJEKT wieder
        freigegeben wird (Freigabe-Ereignis). Es hängt vom Modus des Event
        Profilers ab, wie er sich bei diesem Ereignis verhält. Dies wird im
        folgenden beschrieben.

     Der Event Profiler kann in zwei verschiedenen Modi gestartet werden:

     -  Im Modus PROFILING wird die Geschichte aller erzeugten OBJEKTE mit-
        protokolliert. Wenn ein OBJEKT freigegeben wird, werden alle im
        Event Profiler gespeicherten Informationen für dieses OBJEKT frei-
        gegeben. Die Zeitstempel, die vom Event Profiler zu jedem Ereignis
        mit abgespeichert werden, ermöglichen es dem Systemprogrammierer,
        Speicherfresser zu finden. Wenn ein OBJEKT z. B. vor einer Stunde
        erzeugt worden ist, ist es ein möglicher Kandidat für einen Spei-
        cherfresser.

     -  Im Modus MFREE können mehrfache Freigaben erkannt werden. Wenn ein
        OBJEKT freigegeben wird, werden nicht alle Informationen zu diesem
        OBJEKT freigegeben. Statt dessen wird ein Freigabe-Ereignis mit der
        Aufrufverkettung gespeichert. Wenn das OBJEKT nochmals freigegeben
        wird, kann der Event Profiler dies anhand dieses Ereignisses fest-
        stellen. Normalerweise wird in diesem Fall ein PANIC ausgelöst.
        Anhand der in dem Freigabe-Ereignis gespeicherten Aufrufverkettung
        kann der Systemprogrammierer den ersten Freigeber finden. Anhand
        der Aufrufverkettung des Prozesses, der den PANIC ausgelöst hat,
        kann der zweite Freigeber lokalisiert werden.

     Die Stelle im Code, an der dem Event Profiler ein Ereignis mitgeteilt
     wird, indem eine der ep-Ereignisfunktionen (siehe unten) aufgerufen
     wird, wird als Tracepunkt bezeichnet.

     Damit der Entwickler steuern kann, welche Ereignisse ihn für einen
     bestimmten Fall interessieren, erhalten die Tracepunkte alle eindeu-
     tige Nummern, die Trace-IDs. Diese Nummern bestehen aus Bitmasken, in
     denen nur ein einziges Bit gesetzt ist. Über eine globale Bitmaske -
     die sogenannte Trace-Maske - kann dann durch das Setzen der jeweiligen
     Bits festgelegt werden, welche Tracepunkte aktiv sind. Die Trace-Maske
     eptracemasks [NummerdesCLIENTS] wird bei der Initialisierung des
     Event Profilers mittels crash(1M) in Abhängigkeit vom Modus gesetzt.







Seite 2                      Reliant UNIX 5.44               Gedruckt 11/98

ep(7)                                                                 ep(7)

     Um mehrere Teile des Kerns gleichzeitig untersuchen zu können, unter-
     scheidet der Event Profiler zwischen sogenannten CLIENTS. Ein CLIENT
     ist ein Teil des Kerns, in den Tracepunkte für den Event Profiler ein-
     gebaut wurden. Wenn z. B. ein Fehler in der Freispeicherverwaltung des
     Kerns gefunden werden soll, muß ein neuer CLIENT definiert werden
     (siehe unten). Dann müssen Tracepunkte in diesen Teil des Kerns einge-
     baut werden. Ein Beispiel für einen Teil des Kerns, für den das
     bereits gemacht wurde, ist Streams.

     CLIENTS werden durch eindeutige Nummern [0, AnzahlderCLIENTS-1]
     gekennzeichnet. Um einen neuen CLIENT anzulegen, muß in sys/ep.h eine
     #define-Anweisung eingefügt werden, die dem Namen des neuen CLIENTS
     eine derartige Nummer zuordnet. Die #define-Anweisung EPCLIENTLAST
     muß angepaßt werden, so daß es nach wie vor die letzte verwendete Num-
     mer angibt. Dann muß der Startwert für die Trace-Maske für diesen
     CLIENT (eptracemasks [neueCLIENT-Nummer]) auf ~0 gesetzt werden.
     Dies bedeutet, daß alle Tracepunkte aktiv sind.

     Die Funktionen, über die dem Event Profiler die Ereignisse mitgeteilt
     werden können, haben alle folgende gemeinsame Parameter:

     traceid      Die traceid ist eine pro CLIENT eindeutige Nummer für
                  einen bestimmten Tracepunkt.

     client       client ist die eindeutige Nummer für diesen CLIENT.

     key          key identifiziert das OBJEKT. Hier kann die Adresse eines
                  Puffers verwendet werden, z. B. struct msgb *bp.

     skipcallers  skipcallers gibt die Anzahl von Aufrufern an, die beim
                  Abspeichern der Aufrufverkettung übersprungen werden.
                  Dies ist oft sehr nützlich, wenn die Namen der letzten
                  Aufrufer keine entscheidenden Informationen mehr enthal-
                  ten. Der Wert 0 bedeutet, daß die Speicherung der Aufruf-
                  verkettung beim Aufrufer der ep-Funktion beginnt. Da die-
                  ser jedoch normalerweise über die Nummer des Tracepunktes
                  (Trace-ID) gekennzeichnet ist, wird man normalerweise den
                  Wert 1 verwenden.

     Die Tracepunkte sollten immer im Kern eingebaut bleiben. Nur so ist
     gewährleistet, daß der Event Profiler sofort eingesetzt werden kann,
     sobald ein Fehler auftritt. Damit die Tracepunkte jedoch bei ausge-
     schaltetem Event Profiler nicht unnötig Zeit verbrauchen, wurden die
     Aufrufe der ep-Funktionen in #define-Anweisungen gekapselt. Diese
     rufen die Funkionen nur auf, wenn dies notwendig ist. Deshalb sollten
     nur diese Makros verwendet werden (siehe sys/ep.h). Der Aufruf der
     Makros unterscheidet sich von den korrespondierenden Funktionen nur
     dadurch, daß sie groß geschrieben werden.






Seite 3                      Reliant UNIX 5.44               Gedruckt 11/98

ep(7)                                                                 ep(7)

     Im folgenden werden die ep-Funktionen beschrieben:

     void epcreate(ulongt traceid, int client, ulongt key,
          ulongt maxsize, addrt buf, ulongt len, int skipcallers)

          Es wird dem Event Profiler mitgeteilt, daß ein neues OBJEKT
          erzeugt worden ist. Der Event Profiler speichert automatisch das
          Erzeugungs-Ereignis ab.

          maxsize
               Maximale Anzahl von Bytes, die von beliebigen Aufrufen von
               ep-Funktionen innerhalb dieses CLIENTS als trace-spezifische
               Daten abgespeichert werden sollen. Diese Zahl muß bei allen
               epcreate()-Aufrufen innerhalb dieses CLIENTS gleich sein.

          buf  Adresse der trace-spezifischen Daten oder NULL.

          len  Länge der trace-spezifischen Daten für dieses Ereignis oder
               0. Diese Länge muß natürlich immer kleiner als maxsize sein.

     void epdestroy(ulongt traceid, int client, ulongt key, int skipcallers)

          Es wird dem Event Profiler mitgeteilt, daß das OBJEKT wieder
          freigegeben wurde.

     void eppush(ulongt traceid, int client, ulongt key,
          addrt buf, int len, int skipcallers)

          Es wird ein weiteres Ereignis im Event Profiler gespeichert.

          buf  Adresse der trace-spezifischen Daten oder NULL.

          len  Länge der trace-spezifischen Daten für dieses Ereignis oder
               0. Diese Länge muß natürlich immer kleiner als die bei
               epcreate() verwendete maxsize sein.

     Zusätzlich zu diesen Ereignis-Funktionen wird noch eine weitere Funk-
     tionen zur Verfügung gestellt:

     int epgetcallers(int client, ulongt *buf, int skipcallers)

          Diese Funktion kann verwendet werden, um in einem trace-spezifi-
          schen Datenpuffer die Aufrufverkettung zu speichern. Die Funktion
          gibt die Anzahl der gespeicherten Aufrufer zurück. Falls weniger
          Aufrufer gespeichert werden konnten als für diesen CLIENT mittels
          crash konfiguriert worden ist, wird der Rest mit NULL aufgefüllt.

          buf  Adresse eines Puffers, in den die Aufrufverkettung gespei-
               chert werden soll.





Seite 4                      Reliant UNIX 5.44               Gedruckt 11/98

ep(7)                                                                 ep(7)

   CLIENT: Streams
     Ein erster CLIENT, für den Tracepunkte eingebaut worden sind, ist
     Streams. Ziel des Event Profilers ist es, Speicherfresser oder dop-
     pelte Freigaben von Streams-Nachrichtenblöcken zu entdecken. Deshalb
     wurden die folgenden Tracepunkte eingebaut:

     _________________________________________
    | Funktion   Trace-ID   Ereignis-Funktion|
    |________________________________________|
    | allocb     0x1        epcreate()      |
    | dupb       0x2        epcreate()      |
    | getq       0x4        eppush()        |
    | getq       0x8        eppush()        |
    | putq       0x10       eppush()        |
    | putbq      0x20       eppush()        |
    | putnext    0x40       eppush()        |
    | freeb      0x80       epdestroy()     |
    | freeb      0x100      epdestroy()     |
    | freeb      0x200      epdestroy()     |
    | freeb      0x400      epdestroy()     |
    | freeb      0x800      epdestroy()     |
    | freeb      0x1000     epdestroy()     |
    |________________________________________|

     Da freeb() sechs verschiedene Aufrufe zu freemsgblock() und
     freemdbblock() enthält, gibt es sechs verschiedene Trace-IDs für
     freeb() in der obigen Liste.

BEISPIELE
     Um einen Streams-Nachrichtenblock zu identifizieren, wird neben der
     Adresse des Nachrichtenkopfes noch die Adresse des Datenkopfes benö-
     tigt. Deshalb verwendet Streams spezielle Makros, die in trace-spezi-
     fischen Datenpuffern zusätzlich zur Aufrufverkettung noch die Adresse
     des Datenkopfes speichern:

     #define EPPROFILING
     #ifdef EPPROFILING
     #include "sys/ep.h"

     #define ME      EPCLIENTSTREAMS

     #define EPSTRINITBUF(mp)\
              epclntstreamst buf;\
              int n = epgetcallers(ME, &buf.stk[0], 1);\
              buf.datab = (ulongt)(((struct msgb *)(mp))->bdatap)

     #define EPSTRNEW(mask, mp)\
              if (epactive[ME]) {\
                 EPSTRINITBUF(mp);\
                 epcreate(mask, ME, (ulongt)(mp), (n+1) * sizeof(ulongt),\
                         (addrt)&buf, (n+1) * sizeof(ulongt), 0);\
             }


Seite 5                      Reliant UNIX 5.44               Gedruckt 11/98

ep(7)                                                                 ep(7)

     #define EPSTRLOG(mask, mp)\
              if (epclients[ME]) {\
                 EPSTRINITBUF(mp);\
                 eppush(mask, ME, (ulongt)(mp), (addrt)&buf,\
                         (n+1) * sizeof(ulongt), 0);\
             }
     #define EPSTRDELETE(mask, mp)\
              if (epclients[ME])\
                 epdestroy(mask, ME, (ulongt)mp, 1);
     #endif

     Ein Tracepunkt in freeb() sieht dann z. B. so aus:
         ...

         EPSTRDELETE(0x80, bp);
         freemsgblock(bp);

SIEHE AUCH
     crash(1M).



































Seite 6                      Reliant UNIX 5.44               Gedruckt 11/98

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026