DCI4 Statistic Interface


Copyright (C) 1994 ANT Limited., PO BOX 300, Cambridge, England. All rights reserved.

Redistribution and use in source code and executable binary forms are permitted provided that: (1) source distributions retain this entire copyright notice and comment, and (2) distributions including executable binaries contain the following acknowledgement:

``This product includes software developed by ANT Limited and its contributors. Copyright (C) ANT Limited 1994.''

and also in the documentation and other materials provided with the distribution and in all advertising materials mentioning features or use of this software. Neither the name of ANT Limited nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

This software is provided ``as is'' and without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose.

Not intended for use in life critical applications.


Issue 1 - 23rd September 1994. Borris
Tried to get the basic ideas into a coherent document.

Issue 2 - 25th September 1994. Borris
Changed precise details of register updating on return from some of the swi operations.

Issue 3 - October 1994. Borris
Listened to feedback from reviewers. Adjust underlying model and streamlined most aspects. Added details of suggested scheme for atomic sampling. This issue not widely distributed.

Issue 4 - 7th November 1994. Borris
Tided up and checked consistency with reference header file. Added correct service call number. Added comments about effective suppliers and dynamic SWI number possibilities. name_tag as being outstanding added.

Issue 5 - 16th April 2003. Justin Fletcher
Added time and address statistic types. Version number updated to 1.01.


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

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 it's 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 it's 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, it's 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

Service_StatisticEnumerate (Service &A1)

List available statistic suppliers

On entry
   R0 = 0
   R1 = Service_StatisticEnumerate (&A1)
On exit
   R0 = NULL terminated head of linked list of structures
   R1 preserved

Each supplier allocates a small structure from the RMA, initializes 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, this structure is defined as follows:

  typedef struct spctl
     {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;
   struct spctl *next:

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.

unsigned int i_version:

The DCI4 Statistic Interface version that the supplier is implemented against. This is version 101.

unsigned long features:

A bitset of flags defining optional aspects of a supplier. Values are detailed elsewhere.

unsigned int swinumber:

The SWI number through which all other communication with the supplier is performed.

unsigned int max_stat:

The highest statistic number, inclusive, that the supplier provides. This implies a supplier must always supply at least one statistic.

unsigned int type:

This 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 as follows (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 */
unsigned int s_version:

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

char *module:

This is the supplier's module title (as opposed to its help string).

char *title:

This is 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.

char *description:

This is a longer description of the supplier that should convey it's purpose to the user. The gatherer only contracts to print at least the first fifty characters of this string.

unsigned char reset[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.

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 for 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:

On entry
   R1 = First statistic, inclusive
   R2 = Last statistic, inclusive
   R3 = First byte of buffer in memory
   R4 = Number of bytes in buffer
On exit
   R5 = Number of statistics processed
   R6 = Number of bytes of buffer used

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.

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;
   unsigned int type:
     This defines the type of statistic. Possible values 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
     See below for the meaning of these types.
unsigned int format:

This field contains a 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).

unsigned int presentation:

This field dictates how 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.

unsigned int size:

This is the 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.

unsigned int volatility:

This field indicates how volatile a statistic is. The three possible values 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 */
char *name:

This fields points at 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.

unsigned int name_tag:

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

unsigned int spare:

This field is reserved for future use and will be zero.


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 called 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 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 :

  #define SBF_NORMAL   (0)
     The value supplied is 0 if boolean 'false' and any other value for
     boolean 'true'.
  #define 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 :

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

ST_STRING values are string values. Currently, strings are defined using a zero byte as a terminator character {version s 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 :

  #define SSF_ZEROTERM (0)

This is the only defined format, indicating that the string is zero-terminated.

The presentations which this type uses are :

  #define SSP_LITERAL (0)

The string should be presented as supplied.


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:

  #define SIF_UNSIGNED (0x01)

If this bit is set, the value is unsigned. If this bit is clear, the value is signed.

  #define 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 :

  #define SIP_HEXADECIMAL (0)

The value should be presented as a hexadecimal number.

  #define SIP_DECIMAL (1)

The value should be presented as a decimal number.

  #define 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 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 :

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

The presentations which this type uses are :

  #define SAP_NORMAL (0)
There is only this presentation type.

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 :

  #define 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.

  #define STF_CTIME     (1)

The value is a C time() value, measured in seconds since 00:00 1st January 1970.

  #define STF_MONOTONIC (2)

The value is a centisecond value, used by OS_ReadMonotonicTime, measured in seconds since the system started.

The presentations which this type uses are :

  #define 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.

  #define 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'. An 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.

This documentation is copyright 3QD Developments Ltd 2013 and may not be reproduced or published in any form without the copyright holders permission. RISC OS is subject to continuous development and improvement as such all information is reproduced by 3QD Developments Ltd in good faith and is believed to be correct at the time of publication E&OE. 3QD Developments Ltd cannot accept any liability for any loss or damage arising from the use of any information provided as part of the RISC OS Documentation.

HTML document version 1.03 3rd November 2015