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