DCI4 Statistic Interface

Introduction

The maintenance of statistics such as "packets transmitted" for a network interface can greatly assist the system administrator (or user) in a variety of circumstances.

Traditionally, support for such statistics gathering has been irregular and generally limited to direct screen printing. This specification provides a more controlled method of presenting statistics to the user, and permits a single generic display program to cope with all compliant modules.

The following characterise the intentions of this interface specification:

Plus points

  • Simplicity of implementation
  • Single generic statistics display program
  • No essential central information that needs frequent updating
  • Information is for presentation to humans primarily
  • Atomic operations without any latching mechanisms
  • Well behaved with multiple gatherers
  • Well behaved if a supplier unexpectedly disappears
  • Virtually stateless communication

Minus points

  • Not re-entrant - callbacks or user mode code only
  • Restrictive string model
  • Polled interface, rather than event driven
  • Only simple flat structure to statistics
  • Only really suitable for human display

Technical Details

Basics of operation

A piece of software that wishes to offer statistics is termed a "supplier". A piece of software that obtains statistics from a supplier and presents them to the user is termed a "gatherer", and the operation it performs is often referred to as "enumerating the statistics". There are typically more suppliers than gatherers in a system.

As part of its normal operations, a supplier maintains a set of statistics. A gatherer, typically upon user invocation, enumerates the available suppliers, enumerates the statistics supplied by each supplier and then presents this information to the user. More dynamic presentation is also possible. A supplier is passive (other than its normal operations), whilst the gatherer actively seeks out the information to be presented.

The first stage of enumeration (determining what suppliers are present) is performed with a service call, and the second stage (determining what statistics are available and their values) is performed through a SWI whose SWI number is obtained during the first stage of enumeration. This SWI number is used for all stages of operation apart from enumeration itself.

Each statistic has a number of different pieces of information associated with it, forming its description, and a value. The description provides the necessary information to access and manipulate the value, including the number of bytes of storage required for the value, its type, format and desired presentation. The data types supported are boolean, integer and string. An unused data type also provides for padding.

Descriptions and statistics are read in ranges from a lower statistic number to an upper statistic number, inclusive. The first statistic of any supplier is zero. The highest statistic number of a supplier is obtained when the SWI number for a supplier is obtained. A range is always processed atomically by the supplier, ensuring consistent values and presentation to a gatherer when so required. A supplier indicates the volatility of its statistics and typically attempts to group statistics into ranges of the same volatility.

Enumerating suppliers

The suppliers are enumerated with Service_StatisticEnumerate. Each supplier allocates a small structure from the RMA, initialises it and links it into the linked list whose head is pointed to by R0. Whether the supplier adds an entry at the head or tail of the list does not matter. If a gatherer requires any specific order, then it should explicitly sort the suppliers list itself. A gatherer should not cache SWI values across invocations of suppliers, as a module might choose a dynamic SWI numbering scheme if it offers multiple effective suppliers.

In C, the structure is defined as follows:

typedef struct spctl
{
struct spctl *next; /* Next structure in list */
unsigned int i_version; /* Interface version */
unsigned long features; /* Combination of SF_ values */
unsigned int swinumber; /* The SWI SA_DESCRIBE/SA_READ use */
unsigned int max_stat; /* Highest stat number (inclusive) */
unsigned int type; /* Acorn assigned supplier type */
unsigned int s_version; /* Supplier version */
char *module; /* Module name (short one) */
char *title; /* Title string - short */
char *description; /* Descriptive string - long */
unsigned char reset[8]; /* Unique for each invocation */
} dci4_spctl;

and its fields are:

OffsetNameContents
0nextPointer to the next structure in the list. This field is used to construct the linked list of suppliers for the enumeration operation. A value of zero indicates the end of the list.
4i_versionThe DCI4 Statistic Interface version that the supplier is implemented against. This is version 101.
8featuresA bitset of flags defining optional aspects of a supplier. Values are detailed elsewhere.
12swinumberThe SWI number through which all other communication with the supplier is performed.
16max_statThe highest statistic number, inclusive, that the supplier provides. This implies a supplier must always supply at least one statistic.
20typeThis field is available to provide some classification of suppliers. It is the only centrally administered resource in this specification, and its use is optional. The currently defined values are given below.
24s_versionThis is the version number of the supplier module itself (as opposed to the version number of an interface it conforms to). It is provided for the convenience of the user.
28modulePointer to the supplier's module title (as opposed to its help string).
32titlePointer to a short descriptive string to identify the supplier to the user. The gatherer only contracts to print at least the first twenty characters of this string.
36descriptionPointer to a longer description of the supplier that should convey its purpose to the user. The gatherer only contracts to print at least the first fifty characters of this string.
40reset[8]This 8 byte field is initialised with a unique value each time the supplier is initialised. It permits the gatherer to spot a supplier that has just re-initialised. The time and date at which the supplier initialises are recommended values to write here. The gatherer performs an 8 byte equality test and otherwise assumes no further format information about these bytes.

The supplier types currently defined are (expressed in C):

#define SPT_GENERAL_SUPPLIER 0  /* Use this if no other suitable type */
#define SPT_NETWORK_PROTOCOL 1 /* A DCI4 protocol module */
#define SPT_NETWORK_DRIVER 2 /* A DCI4 device driver module */
#define SPT_MBUF_MANAGER 3 /* The DCI4 mbuf manager module */

When a gatherer has finished interacting with a supplier, it should free the allocated structure back into the RMA.

Communicating with a supplier

Apart from the enumeration phase, all communication with a supplier is performed through the single SWI number obtained during the enumeration phase. The action performed by this "statistic SWI" is controlled by R0 on entry, which contains an action code. The defined action codes are:

SA_DESCRIBE      0
SA_READ 1

SA_DESCRIBE obtains descriptions of statistics, whilst SA_READ obtains the actual values of statistics. It is necessary to first obtain the description of a statistic before reading it, as the description is the only way the gatherer can obtain the size of the statistic value and know how much buffer space to allocate.

The register usage for both SA_DESCRIBE and SA_READ is very similar. In essence, both these actions enumerate information about a range of statistics into the buffer supplied. This is performed atomically, where necessary, by the supplier. In both cases, the operation starts from the first statistic and proceeds in steps of one and stops once the last statistic has been processed. Output is placed into the buffer supplied. If this buffer is not big enough for the requested range of statistics, then processing will stop when it is no longer possible to write all the necessary information for a statistic (ie if the buffer supplied is not big enough, the number of unused bytes will be less than the size of a statistic description). Return values of the number of statistics processed and the number of bytes of the buffer used are returned. The buffer must be word aligned in memory.

Statistic descriptions

Each statistic is described with a fixed sized buffer, described in C as follows:

typedef struct stdesc
{
int type; /* ST_ series */
unsigned int format; /* SxF_ series */
unsigned int presentation; /* SxP_ series */
unsigned int size; /* Measured in bytes */
unsigned int volatility; /* SV_ series */
char *name; /* String is static */
unsigned int name_tag; /* See specification */
unsigned int spare; /* Unused. Always zero */
} dci4_stdesc;

and its fields are:

OffsetNameContents
0typeThe type of statistic (the ST_ series, given below).
4formatA value indicating the format of the value. The range of values is specific to each type (all the integer types share a common set of formats and presentations for convenience). Depending upon the type in question, this value may be an enumeration, a bitset of flags or a combination of both (none of the currently defined formats mix enumeration and flag bitsets).
8presentationHow the supplier would like the value to be presented. A gatherer may choose to ignore this value, but only at the risk of presenting the user with incoherent information.
12sizeThe number of bytes the statistic wishes reserved in the buffer for an SA_READ operation. It is always a multiple of four bytes. It is sometimes larger than the actual value necessary.
16volatilityHow volatile a statistic is (the SV_ series, given below).
20namePointer to the name of the statistic. It is a short descriptive string that the gatherer contracts to display at least the first twenty characters of. The string itself is static, zero byte terminated and contained with the supplier module.
24name_tagThis value, together with the information contained in the dci4_spctl structure and a ISV/IHV supplied data file permit the gatherer to obtain a description of a statistic. The precise mechanism has yet to be determined.
28spareThis field is reserved for future use and will be zero.

The possible values of the type field are:

#define ST_UNUSED           0
#define ST_BOOLEAN 1
#define ST_STRING 2
#define ST_INTEGER8 3
#define ST_INTEGER16 4
#define ST_INTEGER32 5
#define ST_INTEGER64 6
#define ST_ADDRESS 7
#define ST_TIME 8

The three possible values of the volatility field are:

#define SV_STATIC           0       /* Constant per invocation */
#define SV_VARIABLE 1 /* Unlikely to have changed in 5 minutes */
#define SV_VOLATILE 2 /* Can change very rapidly */

Statistic types

ST_UNUSED

ST_UNUSED is used by a supplier to reserve a statistic number. Such a statistic always has a value occupying zero bytes, and hence can always be enumerated, no matter how many bytes are left in the caller supplied buffer. A statistic with a type of ST_UNUSED should always be skipped over when printing and enumerating - none of the fields beyond the type and size fields are valid for unused statistics.

ST_BOOLEAN

ST_BOOLEAN values are single bit boolean values. A variety of different presentation methods may be selected by the supplier in order to maximise coherence between the description and the presentation of a boolean value. Only the least significant bit of a boolean type has a defined value.

The formats which this type uses are:

FormatMeaning
SBF_NORMAL (0)The value supplied is 0 if boolean 'false' and any other value for boolean 'true'.
SBF_INVERTED (1)The boolean state is inverted, 0 if boolean 'true' and any other value for boolean 'false'.

The presentations which this type uses are:

PresentationMeaning
SBP_ON_OFF (0)The strings 'on' and 'off' will be used.
SBP_YES_NO (1)The strings 'yes' and 'no' will be used.
SBP_TRUE_FALSE (2)The strings 'true' and 'false' will be used.
SBP_ALWAYS_NEVER (3)The strings 'always' and 'never' will be used.
SBP_ONE_ZERO (4)The strings '1' and '0' will be used.

ST_STRING

ST_STRING values are string values. Currently, strings are defined using a zero byte as a terminator character (later versions may well introduce counted length strings as well). A supplier is required to be able to place an upper length value on all strings so that sufficient space may be allocated within the caller supplied buffer for the SA_READ operation.

The formats which this type uses are:

FormatMeaning
SSF_ZEROTERM (0)This is the only defined format, indicating that the string is zero-terminated.

The presentations which this type uses are:

PresentationMeaning
SSP_LITERAL (0)The string should be presented as supplied.

ST_INTEGERx

ST_INTEGERx values are all integer values. A variety of different sized integers are supported to suit different requirements. A flexible set of presentation methods is supported.

The formats which this type uses are a bit field:

FormatMeaning
SIF_UNSIGNED (0x01)If this bit is set, the value is unsigned. If this bit is clear, the value is signed.
SIF_BIGENDIAN (0x02)If this bit is set, the value is supplied as big-endian. If this bit is clear, the value is supplied as little-endian.

The presentations which this type uses are:

PresentationMeaning
SIP_HEXADECIMAL (0)The value should be presented as a hexadecimal number.
SIP_DECIMAL (1)The value should be presented as a decimal number.
SIP_DOTTED (2)The value should be presented separating every octet with a '.' character. This was intended for use for addresses; it has been superseded by the ST_ADDRESS type.

ST_ADDRESS

ST_ADDRESS values are network address values. A number of different formats of address are supported. This type is only available in version 1.01 of the statistics interface.

The formats which this type uses are:

FormatMeaning
SAF_ETHERNET (0)The value is a 6 byte MAC address. A value of 0 indicates no address.
SAF_IP (1)The value is a 4 byte IP address. A value of 0 indicates no address.
SAF_ECONET (2)The value is a 2 byte (net.station) address.

The presentations which this type uses are:

PresentationMeaning
SAP_NORMAL (0)There is only this presentation type.

ST_TIME

ST_TIME values are times when events occurred, or will occur. This type is only available in version 1.01 of the statistics interface.

The formats which this type uses are:

FormatMeaning
STF_5BYTE (0)The value is a standard 5 bytes format (8 bytes, top 3 bytes ignored), measured in centiseconds since 00:00 1st January 1900.
STF_CTIME (1)The value is a C time() value, measured in seconds since 00:00 1st January 1970.
STF_MONOTONIC (2)The value is a centisecond value, as used by OS_ReadMonotonicTime, measured in centiseconds since the system started.

The presentations which this type uses are:

PresentationMeaning
STP_ABSOLUTE (0)The values are absolute and should be presented as time values from their reference base. An absolute value of 0 indicates that no time has been specified.
STP_RELATIVE (1)The values are relative to the current time, and the reference base should be ignored. For example, a value of 250 in format STF_MONOTONIC might be presented as '2.50 seconds'. A relative value of 0 indicates that no period has been given.

Ping pong atomicity

The supplier is required to perform each read request atomically. This means a gatherer can rely upon a read operation producing consistent statistics, but it cannot be certain quite when in time these statistics apply to; in some cases, statistics are virtually always out of date by the time the gatherer obtains and uses them.

The simplistic approach to ensuring an atomic read operation is to perform the entire action with interrupts disabled. This, however, has an undesirable effect on interrupt latency for suppliers with many or complex statistics and is not recommended.

The suggested method is a three buffer scheme. One buffer holds the accumulated statistics, the second holds the increments (deltas) being generated "live", and the third is either entirely full of zero values, or there is an active read operation in progress and it holds a previous set of increments that are currently being added (merged) into the accumulated values.

Two pointers are maintained. One for the "live" buffer and the other for the "merge" buffer. The operation that is necessary to perform atomically is the swapping of these two pointer values.

The overall structure suggested is as follows:

start thread of control (ie SWI)
enter mutex (eg disable interrupts)
temp := buffer pointer 1
buffer pointer 1 := buffer pointer 2
buffer pointer 2 := temp
exit mutex (and ensure interrupts enabled)
add values from buffer pointer 2 into the accumulated values
zero the memory described by buffer pointer 2
end thread of control (ie SWI)

This maximises the usefulness of the non re-entrancy requirement and requires ONLY the swapping of the buffer pointers to be performed atomically. All other operations can proceed with interrupts enabled. This minimal critical region is the prime motivation behind this scheme.

Additional notes

Some applications of the statistic interface will require a single RISC OS module to behave as multiple suppliers. For example, a device driver module that controls multiple interfaces might well wish to provide an overall set of statistics, and then an instance of a set of statistics per interface controlled. A separate SWI number is required for each 'effective supplier'. This is not normally a problem, as very few modules approach the limit of the 64 separate SWIs allocated. Gatherers are expected to obtain SWI numbers through the enumeration method supplied, and should be capable of handling dynamic SWI number assignment. For example, a device driver may choose SWIs 63, 62 and 61 for units 0, 1 and 2, respectively. If a gatherer were to attempt to 'cache' these SWI numbers across invocations of the device driver, then it might not correctly cater for the addition or removal of interfaces.

Service Calls

Service_StatisticEnumerateService Call &A1
List available statistic suppliers
R0=0
R1=&A1 (Service_StatisticEnumerate)
R0=NULL terminated head of linked list of structures
R1preserved

Each supplier allocates a small structure from the RMA, initialises it and links it into the linked list whose head is pointed to by R0. See Enumerating suppliers for the structure.

Entry points

StatisticSWI 0SA_DESCRIBE
Obtain descriptions of a range of statistics
R0=0 (SA_DESCRIBE)
R1=First statistic, inclusive
R2=Last statistic, inclusive
R3=First byte of buffer in memory
R4=Number of bytes in buffer
R5=Number of statistics processed
R6=Number of bytes of buffer used
Interrupts are undefined
Fast interrupts are undefined
Processor is in undefined mode
Entry point is not re-entrant

This is the action of the statistic SWI (the SWI whose number is the swinumber of the supplier) which writes a dci4_stdesc structure for each statistic in the range into the buffer. The description of a statistic must be read before its value, as it gives the size of the value. The buffer must be word aligned, and the SWI is not re-entrant.

StatisticSWI 1SA_READ
Obtain the values of a range of statistics
R0=1 (SA_READ)
R1=First statistic, inclusive
R2=Last statistic, inclusive
R3=First byte of buffer in memory
R4=Number of bytes in buffer
R5=Number of statistics processed
R6=Number of bytes of buffer used
Interrupts are undefined
Fast interrupts are undefined
Processor is in undefined mode
Entry point is not re-entrant

This is the action of the statistic SWI which writes the value of each statistic in the range into the buffer, using the number of bytes given in the size field of its description. The range is read atomically by the supplier. The buffer must be word aligned, and the SWI is not re-entrant.