Ravenbrook / Projects / Memory Pool System / Master Product Sources / Design Documents

Memory Pool System Project


               THE DESIGN OF THE MPS TELEMETRY MECHANISM
                          design.mps.telemetry
                           incomplete design
                           richard 1997-07-07


INTRODUCTION:

This documents the design of the telemetry mechanism within the MPS.

.readership: This document is intended for any MPS developer.

.source: Various meetings and brainstorms, including 
meeting.general.1997-03-04(0), mail.richard.1997-07-03.17-01(0), 
mail.gavinm.1997-05-01.12-40(0).


Document History

.hist.0: 1997-04-11  GavinM  Rewritten

.hist.1: 1997-07-07  GavinM  Rewritten again after discussion in Pool Hall.


OVERVIEW:

Telemetry permits the emission of events from the MPS.  These can be used to 
drive a graphical tool, or to debug, or whatever.  The system is flexible and 
robust, but doesn't require heavy support from the client.


REQUIREMENTS:

.req.simple: It must be possible to generate code both for the MPS and any tool 
without using complicated build tools.

.req.open: We must not constrain the nature of events before we are certain of 
what we want them to be.

.req.multi: We must be able to send events to multiple streams.

.req.share: It must be possible to share event descriptions between the MPS and 
any tool.

.req.version: It must be possible to version the set of events so that any tool 
can detect whether it can understand the MPS.

.req.back: Tools should be able to understand older and newer version of the 
MPS, so far as is appropriate.

.req.type: It must be possible to transmit a rich variety of types to the tool, 
including doubles, and strings.

.req.port: It must be possible to transmit and receive events between different 
platforms.

.req.control: It must be possible to control whether and what events are 
transmitted at least at a coarse level.

.req.examine: There should be a cheap means to examine the contents of logs.

.req.pm: The event mechanism should provide for post mortem to detect what 
significant events led up to death.

.req.perf: Events should not have a significant effect on performance when 
unwanted.

.req.small: Telemetry streams should be small.

.req.avail: Events should be available in all varieties, subject to performance 
requirements.

.req.impl: The plinth support for telemetry should be easy to write and 
flexible.

.req.robust: The telemetry protocol should be robust against some forms of 
corruption, e.g. packet loss.

.req.intern: It should be possible to support string-interning.


ARCHITECTURE:

.arch: Event annotations are scattered throughout the code, but there is a 
central registration of event types and properties.  Events are written to a 
buffer via a specialist structure, and are optionally written to the plinth.  
Events can take any number of parameters of a range of types, indicated as a 
format both in the annotation and the the registry.


ANALYSIS:

.anal: The proposed order of development, with summary of requirements impact 
is as follows:

                        v      c e 
               s        e      o x             r  i
               i   m  s r      n a      s  a   o  n
               m o u  h s t  p t m    p m  v i b  t b
               p p l  a i y  o r i    e a  a m u  e a
               l e t  r o p  r o n  p r l  i p s  r c
               e n i  e n e  t l e  m f l  l l t  n k

.sol.format    0 0 0  0 0 +  0 0 0  0 0 0  0 0 0  0 0  Merged.
.sol.struct    0 0 0  0 0 +  0 0 0  0 + -  0 0 0  0 0  Merged.
.sol.string    0 0 0  0 0 +  0 0 0  0 0 0  0 0 0  + 0  Merged.
.sol.relation  + 0 0  + 0 0  0 0 +  0 0 +  0 0 0  0 0  Merged.
.sol.dumper    0 0 0  0 0 0  0 0 +  0 0 0  0 0 0  0 0  Merged.
.sol.kind      0 - 0  0 0 0  0 + 0  + 0 0  0 0 0  0 0  Merged.
.sol.control   0 0 0  0 0 0  0 + 0  0 + 0  0 0 0  0 0  Merged.

.sol.variety   0 0 0  0 0 0  0 0 0  + + 0  + 0 0  0 0

[ Not yet ordered. ]

.sol.buffer    0 0 0  0 0 0  0 + 0  + + 0  0 0 0  0 0
.sol.traceback 0 0 0  0 0 0  0 0 0  + 0 0  0 0 0  0 0
.sol.client    0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  + 0
.sol.head      0 0 0  0 0 0  + 0 0  0 0 0  0 0 0  0 0
.sol.version   0 0 0  0 + 0  0 0 0  0 0 0  0 0 0  0 +
.sol.exit      0 0 0  0 0 0  0 0 0  + 0 0  0 0 0  0 0
.sol.block     0 0 0  0 0 0  0 0 0  0 + -  0 0 +  0 0 
.sol.code      0 0 0  0 0 0  0 0 0  0 0 +  0 0 0  0 +
.sol.msg       0 0 +  0 0 0  + 0 0  0 0 0  0 + +  0 0

.file-format: One of the objectives of this plan is to minimise the impact of 
the changes to the log file format.  This is to be achieved firstly by 
completing all necessary support before changes are initiated, and secondly by 
performing all changes at the same time.


IDEAS:

.sol.format: Event annotations indicate the types of their arguments, e.g. 
EVENT_WD for a Word, and a double.  (.req.type)

.sol.struct: Copy event data into a structure of the appropriate type, e.g. 
EventWDStruct.  (.req.type, .req.perf, but not .req.small because of padding)

.sol.string: Permit at most one string per event, at the end, and use the char 
[1] hack, and specialised code; deduce the string length from the event length 
and also NUL-terminate  (.req.type, .req.intern)

.sol.buffer: Enter all events initially into internal buffers, and 
conditionally send them to the message stream. (.req.pm, .req.control, 
.req.perf)

.sol.variety: In optimized varieties, have internal events (see .sol.buffer) 
for a subset of events and no external events; in normal varieties have all 
internal events, and the potential for external events.  (.req.avail, .req.pm, 
.req.perf)

.sol.kind: Divide events by some coarse type into around 6 groups, probably 
related to frequency.  (.req.control, .req.pm, but not .req.open)

.sol.control: Hold flags to determine which events are emitted externally.  
(.req.control, .req.perf)

.sol.dumper: Write a simple tool to dump event logs as text.  (.req.examine)

.sol.msg: Redesign the plinth interface to send and receive messages, based on 
any underlying IPC mechanism, e.g. append to file, TCP/IP, messages, shared 
memory.  (.req.robust, .req.impl, .req.port, .req.multi)

.sol.block: Buffer the events and send them as fixed size blocks, commencing 
with a timestamp, and ending with padding.  (.req.robust, .req.perf, but not 
.req.small)

.sol.code: Commence each event with two bytes of event code, and two bytes of 
length.  (.req.small, .req.back)

.sol.head: Commence each event stream with a platform-independent header block 
giving information about the session, version (see .sol.version), and file 
format; file format will be sufficient to decode the (platform-dependent) rest 
of the file.  (.req.port)

.sol.exit: Provide a mechanism to flush events in the event of graceful sudden 
death.  (.req.pm)

.sol.version: Maintain a three part version number for the file comprising 
major (incremented when the format of the entire file changes (other than 
platform differences)), median (incremented when an existing event changes its 
form or semantics), and minor (incremented when a new event type is added); 
tools should normally fail when the median or major is unsupported.  
(.req.version, .req.back)

.sol.relation: Event types will be defined in terms of a relation specifying 
their name, code, optimised behaviour (see .sol.variety), kind (see .sol.kind), 
and format (see .sol.format); both the MPS and tool can use this by suitable 
#define hacks.  (.req.simple. .req.share, .req.examine, .req.small (no format 
information in messages))

.sol.traceback: Provide a mechanism to output recent events (see .sol.buffer) 
as a form of backtrace when AVERs fire or from a debugger, or whatever. 
(.req.pm)

.sol.client: Provide a mechanism for user events.  (.req.intern)



IMPLEMENTATION:

Annotation

.annot: An event annotation is of the form:
  EVENT_PAW(FooCreate, pointer, address, word);

.annot.format: Note that the format is indicated in the macro name.  See 
.format.

.annot.string: If there is a string in the format, it must be the last 
parameter (and hence there can be only one).  There is currrently a maximum 
string length, defined by EventMaxStringLength in impl.h.eventcom.

.annot.type: The event type should be given as the first parameter to the event 
macro, as registered in impl.h.eventdef.

.annot.param: The parameters of the event should be given as the remaining 
parameters of the event macro, in order as indicated in the format.


Registration

.reg: All event types should be registered in impl.h.eventdef, in the form of a 
relation. 

.reg.just: This use of a relation macro enables great flexibility in the use of 
this file.

.reg.rel: The relation is of the form:
  RELATION(FooCreate, 0x1234, TRUE, Arena, PAW)

.reg.type: The first parameter of the relation is the event type.  This needs 
no prefix, and should correspond to that used in the annotation.

.reg.code: The second parameter is the event code, a 16-bit value used to 
represent this event type.  [Not yet used.  GavinM 1997-07-18]

.reg.code.temp: On an interim basis, new events also have to be registered in 
impl.h.eventcom.  This will no longer be required when the event file format is 
revised. 

.reg.always: The third parameter is a boolean value indicating whether this 
event type should be implemented in all varieties.  See .control.buffer.  
Unless your event is on the critical path (typically per reference or per 
object), you will want this to be TRUE.

.reg.kind: The fourth parameter is a kind keyword indicating what category this 
event falls into.  See .control.  The possible values are:
  Arena -- per space or arena or global
  Pool -- pool-related
  Trace -- per trace or scan
  Seg -- per segment
  Ref -- per reference or fix
  Object -- per object or allocation
This list can be seen in impl.h.event.

.reg.format: The fifth parameter is the format (see .format) and should 
correspond to the annotation (see .annot.format).

.reg.dup: It is permissible for the one event type to be used for more than one 
annotation.  There are generally two reasons for this:
  - Variable control flow for successful function completion;
  - Platform/Otherwise-dependent implementations of a function.
Note that all annotations for one event type must have the same format (as 
implied by .reg.format).


Format

.format: Where a format is used to indicate the type, it is a sequence of 
letters from the following list:
  P -- void *
  A -- Addr
  W -- Word
  U -- unsigned int
  S -- char *
  D -- double
The corresponding event parameters must be assignment compatible with these 
types.

.format.zero: If there are no parameters for an event, then the special format 
"0" should be used.

.format.types: When an event has parameters whose type is not in the above 
list, use the following guidelines: All C pointer types not representing 
strings use P; Size and Count use W; *Set use U; others should be obvious.

.format.support: Every format used needs bespoke support in impl.h.eventgen.  
It has not been possible to provide support for all possible formats, so such 
support is added when required.  .format.support.auto: There is a tool in 
impl.pl.eventgen that will generate impl.h.eventgen automatically.  It is used 
as follows:
  1. Claim the file eventgen.h.
  2. Invoke eventgen.pl.
  3. Check it compiles correctly in all varieties.
  4. Check in eventgen.h.


Control

.control: There are two types of event control, buffer and output.

.control.buffer: Buffer control affects whether particular events implemented 
at all, and is controlled statically by variety using the always value (see 
.reg.always) for the event type.  This is only relevant to release varieties.  
[Not yet implemented.  GavinM 1997-07-18]

.control.output: Output control affects whether events written to the internal 
buffer are output via the plinth.  This is set on a per-kind basis (see 
.reg.kind), using a control bit table stored in EventKindControl.  By default, 
all event kinds are on (in variety.ti).  You may switch some kinds off using a 
debugger.

For example, to disable Ref events using gdb (see impl.h.event for numeric 
codes):

  break ArenaCreate
  run
  delete 1
  call BTRes(EventKindControl, 4)
  continue

.control.just: These controls are coarse, but very cheap.

.control.external: There will be an MPS interface function to control 
EventKindControl.

.control.tool: The tools will be able to control EventKindControl.


Dumper Tool

.dumper: A primitive dumper tool is available in impl.c.eventcnv.  For details, 
see guide.mps.telemetry.


Allocation Replayer Tool

.replayer: A tool for replaying an allocation sequence from a log is available 
in impl.c.replay.  For details, see design.mps.telemetry.replayer.



TEXT:

.notes:
  - Set always to FALSE for all Ref and Object events;
  - Fix use of BT for size in bytes, guess then check, BTInit;
  - Resolve protection transgression in impl.h.eventdef;
  - Make EventKind* enum members so they can be used from the debugger.

A. References

B. Document History

2002-06-07 RB Converted from MMInfo database design document.