Previous section.

UMA Data Capture Interface (DCI)
Copyright © 1997 The Open Group

Overview of the DCI Specification

This is the specification for the Data Capture Interface. The material in this chapter is authoritative and overrides any possibly conflicting material in the first two chapters of this document. This and the next chapter cover the following material:

Conventions

Naming Conventions

This section follows a naming convention for the three types of programming language constructs defined here: constants, type definitions, and routine names. (The rules followed are the same as those followed by the MLI layer (see reference MLI).) The purpose of this convention is to clearly identify the Data Capture facilities in a program, to determine what type of object a particular DCI name represents, and to avoid name space conflicts.

To this end:

An additional naming convention is that only English alphabetic characters are used. For type definitions and routine names, non-alphabetic characters, such as underscore, are not used as delimiters within a name.

Data Type Conventions

A set of data types has been defined for the DCI. The primary purpose of these data type definitions is to ensure that different DCI implementations support the same data types. All DCI data types are defined in the <uma.h> header file in Part 2 of this publication; they have the uppercase "UMA" prefix, followed by a mixed case name (for example, UMAInt4, UMAUint4, UMAInt8).

Treatment of Variable Length Structures

Many structures in the Data Capture Interface have variable length. For example, metric class identifiers are unconstrained in the number of levels. Further, many variable length structures may themselves be contained in other variable length structures. The DCI has adopted a consistent mechanism for the layout and description of such structures.

Most DCI structures have the same organisation:

Figure: DCI Structure Organisation

Size is the size of the entire structure (including any variable part). The fixed part contains only simple fixed size entities (for example, UMAUint4, DCIDatumId), as well as fixed sized descriptors for any variable length data in the rest of the structure (for example, UMAVarLenDescr). The variable part contains all variable data. It may include many variable structures, each of which is described by a fixed size descriptor in the fixed part of the overall structure.

There are no constraints on the placement of the different variable length structures within the variable part of the overall structure; each descriptor "points" to its corresponding variable part using an offset mechanism - every descriptor contains an offset field which is a byte offset to be applied to the base of the structure in question. Thus the offset field is always a small positive integer. Because the offset is added to the base address of the structure in question and then indirected, it must always produce a correct address within the structure. Variable length data which is optional must have a valid offset to data of 0 size to prevent improper address indirection.

There are different types of descriptors for different types of variable length entities (for example, array of fixed size elements, string, array of variable length elements). Each of these descriptor types is presented in the <uma.h> file, and DCI structures are presented in the <dci.h> file. Each file is a valid/compilable C-language include file. In each of these structures, the variable part is described uniformly as being of type UMAVarLenData; this is simply a placeholder for the entire variable section.

It is worthwhile noting two interesting properties of variable sized DCI structures that result from using descriptors. First is that the order of the data in the variable part of a structure may not be the same as the order of the fixed sized fields that point to it. So for example, if a structure contains descriptors field1and field2, in that order in the fixed part, it is valid for the data pointed at by field2 to precede the data pointed at by field1 in the variable length area. (It is NOT valid for fields to overlap.) Second is that it is also valid for the variable part of a structure to contain "holes" which are never referenced. A hole would be accounted for in the size field of the enclosing structure, but would not be described by any of the descriptors. If individual variable length structures are properly located using the offset field located in their descriptors (located in the fixed part of the overall structure), both these interesting properties will be transparent.

Note that the foregoing discussion applies to most variable length structures; there are some exceptions involving primitive structures (for example, UMATextString) that do not require the flexibility of the offset mechanism, and thus are optimised to be as small and simply-organised as possible.

Metrics Name Space

The Data Capture Interface supports a hierarchical name space that is used to uniquely identify specific instances of available metrics. Metric providers make additions and deletions to the contents of the name space as they make metrics available and unavailable to metrics consumers. Metric consumers query the name space to obtain metric names; these names are used to obtain actual metric values.

The other purposes of this name space are to provide a mechanism for storage of the descriptions of what type of data is available, the metric class attributes, and to provide a hierarchical structure suitable for implementing an access control mechanism.

The metrics name space is grouped into two layers: one layer to identify a metric class, or metric datum within a metric class, and another layer to identify the available instances for a metric class. The first layer is represented by the metric class identifier combined with the metric datum identifier. The second layer is represented by the metric instance identifier. Together the two name space layers uniquely identify a metric instance. The components associated with this name space are the DCIClassId, DCIInstanceId, DCIDatumId. The DCIMetricId is a combination of all three components.

File systems typically store any of their supported object types, such as files or devices, at any position in their name space. The DCI imposes more structure upon its name space by identifying different levels with different object types and restricting the positions at which objects can be stored. The reason behind these restrictions is that the DCI name space is not a general purpose file system but is intended to support a very specific purpose. The structure and function of the DCI name space are described in the following sections.

Mapping DCI Name Space to a Network Representation

One of the primary goals of the DCI name space design is that it map well to a network representation. This section describes how one might approach such a mapping and how this approach affected the name space design.

A fully qualified metric name consists of a metric class identifier, a metric instance identifier and a metric datum identifier. A metric class identifier is a sequence of class levels, where each class level is a 4 byte integer. A metric instance identifier is a sequence of instance levels, where each instance level is a multiple of 4 bytes. Instance levels are intended to represent natural values found within a system; as such, they are not arbitrarily limited in size or range. For a given class, however, the number of instance levels is defined, as is the size of each instance level.

The DCI interfaces allow metrics to be selected individually, or as a group within an instantiated class. The metric datum identifier is a 4 byte integer, with values 0 and 2^32 - 1 reserved. Thus, there are at most 2^32 - 2 unique metric data within any instantiated class.

To summarise, the metrics name space features:

DCI API Data Types

DCI structures do not need the delimiter necessary in the network representation as they can rely on the structure boundaries themselves. The C structures are presented first and then described in subsequent sections. The detailed descriptions include code fragments for how these structures are used.

The structures are defined as follows:

DCIClassId

typedef struct DCIClassId { UMAUint4 size; UMAVarLenData data; } DCIClassId;

The usage of the structure elements is as follows:

size
The total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

data
Variable length data

DCIDatumId

typedef UMAUint4 DCIDatumId;

The usage of the structure elements is as follows:

DCIDatumId
Datum identifier

DCIInstanceId

typedef struct DCIInstanceId { UMAUint4 size; UMAUint4 inputMask; UMAUint4 outputMask; UMAVarLenData data; /* Type: defined by DCIClassAttr */ } DCIInstanceId;

The usage of the structure elements is as follows:

size
The total nutotal number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

inputMask
A bitmap indicating which levels are included in this instance id. Only included levels will have instance identifiers in the data area of this structure. Levels not included (i.e., those for which their corresponding inputMask bit is off, set to 0), are interpreted as wildcarded. Bit 0 corresponds to the first instance level registered for the class; bit 1 for the second, and so on.

outputMask
A bitmap indicating which levels in the instance id to be filled in by the provider/DCI Server. At least one level must be selected (set to 1).

data
Variable length structure holding the single instance identifier. The instance identifier contains a sequence of instance levels; the number of instance levels and the size of each instance level can be found in the DCIClassAttr structure

DCIMetricId

typedef struct DCIMetricId { UMAUint4 size; UMAVarLenDescr classId; /* Type: DCIClassId */ UMAVarLenDescr instanceId; /* Type: DCIInstanceId */ DCIDatumId datumId; UMAVarLenData data; } DCIMetricId;

The usage of the structure elements is as follows:

size
The total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

classId
Indirection to class identifier (variable size)

instanceId
Indirection to instance identifier (variable size)

datumId
Datum identifier

data
Variable length data (DCIClassId and DCIInstanceId structures)

Use of DCI Name Space Structures
The following diagram gives an example of how the name space structures are used. The solid boxes identify individual classes and the dashed boxes instances of those classes. The root of this DCI name space is labeled metrics and is an uninstantiated class. There are two labeled subclasses, one being the data pool and the other an application. The data pool is a predefined group that lists operating system metrics used to describe system behaviour. See the companion document, Data Pool Definitions (see reference DPD), for a list of those metrics.

Figure: Name Space Example

The Data Pool is organised as a class/subclass hierarchy. In Name Space Example there is a processor class with two sample subclasses, global measured processor times and per processor counters. In this example, there are two processor instances of the perprocessorcounters class, but only a single instance of the globalmeasuredprocessortimes class. In the DCI, a class with a single instance is specified with an instance type of UMA_SINGLEINST. The DCI name space class hierarchy is not limited to two class levels, as might be surmised from the accompanying diagram. This is merely a Data Pool convention.

Note that there are measurements available for two instances of the application metric class. These are probably differentiated by the process identifier of each running copy of the application. There is an important point here. The DCI name space class hierarchy is abstract and represents the organisation of metric classes. The DCI name space instance hierarchy represents system values and uses those values directly. In the example, the application metric class can be instantiated by process identifier and the Data Pool's processor metrics by process number. Instantiated classes are simply those classes which can support instances. Uninstantiated classes are simply positions in the name space and provide its hierarchical structure. An instantiated class cannot have subclasses.

Another point that can be drawn from this example is that the DCI is optimised to work with entire metric classes. One can specify individual metrics within an instantiated class by using an explicit value for the datumId in the DCIMetricId structure, but it is expected that this use will be the exception rather than the rule. Usually a single wildcarded datumId would be specified to efficiently obtain all the metrics available within an instantiated class.

The positioning of the datumId below the instance in the name space implies that metrics are consistently provided across all instances of a class. In general, this will be the case. However, there are situations in which it is not possible for certain instances of a class to provide all metrics within the class. As an example, if a subclass were used for disk metrics, one might provide part of the subclass for one disk instance and a different part for a second disk instance.

DCIDatumId Reservation

Special polled and event metrics
The DCIDatumId is a UMAUint4 (32 bit) quantity. Certain values of the DCIDatumId are reserved for special polled metrics and event metrics; further, several DCIDatumId values are reserved for vendor use:
Reserved Polled metric DCIDatumId value DCI_INVALIDDATUMID 0x000000ff Reserved Event metric DCIDatumId value DCI_FINALDATA_EVENT 0x000000f8 DCI_INSTANCEADDED 0x000000f7 DCI_INSTANCEREMOVED 0x000000f6 DCI_DATACHANGED 0x000000f5 Reserved for vendor use 0x000000e8 - 0x000000ef
Support for derivation of metrics
Measurement application developers frequently need to derive reported metrics from the raw metrics available on a system. While the key focus of the DCI is to provide access to the raw metrics, it also supports such derivation through an encoding of the DCIDatumId. This encoding allows metric providers to record relationships between metrics within a class. These relationships can then be interpreted by consumers.

A derived metric is defined by explicitly encoding the manner of its derivation in the derived metric's DatumId. Each derived metric holds a place in the class namespace.

The types of relationships that can be expressed include:

Sum
The derived metric is obtained by adding two other metrics in the class.

Ratio
The derived metric is obtained by taking the ratio of two other metrics in the class.

See Data Types and Measurement Units for a complete description of derived metric support.

Note that derived metric support is limited to the encoding of inter-metric relationships. Each derived metric holds a place in the namespace, but there is no derived data available through the DCI. No actual derivation occurs within the DCI; this remains the responsibility of the consumer.

DCIMetricId Code Sample

A completely named metric consists of the DCIClassId, the DCIInstanceId within that class, and the DCIDatumId. The DCIMetricId contains the size of the sum of the individual parts, so traversing a list of DCIMetricIds becomes a simple task (although complicated by casting requirements due to the variable size of the DCIMetricId structure). The following code performs a traversal of a list of DCIMetricIds having length metricIdListCount:
DCIMetricId *aMetricIdPointer; DCIMetricId aMetricIdList[]; int metricIdListCount;  ... pick up a list of metricIds and its size aMetricIdPointer = aMetricIdList; while (metricIdListCount--) {  ... do something with the current metricId aMetricIdPointer = (DCIMetricId *) ((char *)aMetricIdPointer + aMetricIdPointer->size); }

DCIClassId Code Sample

Although defined as a fixed size structure, the actual metric class identifier is a variable size 4 byte integer array. The DCIMetricId contains a reference to this array by offset, element size and number of elements. The array follows the structure directly, as started by the variable length data declaration.

Thus, to walk the integers in a DCIClassId, the following code fragment could be used:

DCIClassId *aClassId; int i, numlevels; numlevels = dciclassidlen(aClassId); for (i = 0; i < numlevels; i++) { {  ... do something with dciclassidlevel(aClassId, i) }

Note that the size of each array element is always four bytes.

DCIInstanceId

A single metric instance identifier is enclosed in the DCIInstanceId structure. A metric instance identifier is used to select one of otherwise identical groups of metrics. The metric instance identifier is used to distinguish among several instantiations of objects such as disks, processors, processes, etc. Thus a metric instance identifier is closely associated with the object being measured.

The DCI does not reserve any instance values to represent wildcards and therefore the DCIInstanceId contains a bitmask to indicate wildcarding of a particular level in a metric instance identifier. Since these flags are represented as a bitmap in a 4 byte integer (UMAUint4), the maximum number of levels for a metric instance identifier is 32. The bitmap indicates which instance levels are explicitly included in the DCIInstanceId structure; those not explicitly included (i.e., those for which their corresponding bit is off) are wildcarded. The bitmap starts at bit position 0 and the metric instance identifier levels start at level 0.

DCIInstanceId Diagram shows the layout of the DCIInstanceId structure.

The size of the entire DCIInstanceId structure and all its associated variable length data is stored in the size member of the DCIInstanceId structure. Instance levels within a single metric instance identifier can vary in size, but are always a multiple of 4 bytes. The actual information about the instance levels is encoded in the DCIClassAttr structure defined later in this document.

Figure: DCIInstanceId Diagram

DCIInstanceId Structure Examples

The DCIInstanceId structure allows applications to efficiently specify the following:

As an example, consider a metric class which is instantiated on a per-processor, per-disk basis and that both these metric instance identifier level types are four byte values. Specifying the metric instance identifier for processor 1, disk 2 is as shown in DCIInstanceID: Two Instance Levels , assuming that the instance values for processor1 = 1, disk2 = 2. The first instance level value (level 0) specifies the processor and the second one (level 1) the disk. Note that the outputMask is set to 2^32-1 indicating that all instance levels are to be filled in when this DCIInstanceId is returned in any DCIReturn structure.

Figure: DCIInstanceID: Two Instance Levels

Note that the structure sizes would not change if both levels in the above instance were specified as one byte values. There is an implicit four byte padding since the single byte instance must be written to a four byte aligned instance field.

Using the above example, specifying all disks for processor 1 would be as shown in DCIInstanceId: Two Instance Levels, Wildcarding .

Figure: DCIInstanceId: Two Instance Levels, Wildcarding

Note that the second bit (bit 1) in the inputMask is set to 0, indicating that level 1 is wildcarded. The value for level 2 must not be specified. Note that the instance id structure is smaller than the previous example.


Wildcards

Wildcards are used with all three name space levels, classes, instances, and individual metrics. The DCI name space class hierarchy reserves the integer value of 2^32 - 1 (all bits in the integer are set) as the "DCI_ALL" wildcard value for any particular class level. This convention is used to specify groups of metric classes. Any integer in a metric class identifier can be wildcarded. In the case of instance ids, wildcards will always expand into valid instances without error, unless no instances can be found for the class.

Similarly, metric instance identifier levels can be wildcarded. As seen in the previous section's examples, this wildcarding is via a different mechanism than the class identifier. This is because no field of an instance can be reserved for a wildcard value. The wildcard must be specified outside of the instance range. Note that instance levels are wildcarded by setting bits in the inputMask to 0, and that there is a special "DCI_ALL_INSTANCES" inputMask value that wildcards all instance levels.

As noted in DCIInstanceId Structure Examples , the metric datum identifier uses the same wildcard as the metric class identifier, the value 2^32 - 1 ("DCI_ALL"). When this wildcard is used it indicates all metrics in the instantiated class. This also signals that all data is presented as a single entity, rather than broken out by datum identifier separately, as is explained in DCIDataAttr .

Access Control

One of the purposes of a hierarchical name space is to enable the implementation of secure access control mechanisms. This is done by storing access control information at the nodes of the hierarchy. This information can then be used by the DCI Server in cooperation with the underlying operating system to provide discretionary and mandatory access control. Access control can be performed at both the class and instance levels. The DCI access control data type is:
typedef struct DCIAccess { UMAUint4 size; UMAVarLenData access; } DCIAccess;

The usage of the structure elements is as follows:

size
The total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

access
Byte array containing the access information.

The purpose of defining a variable sized field structure is to allow for the wide variation in access control structures between operating systems and differing security levels. A DCIAccess structure for standard UNIX might have a size of twelve and the access field of DCIAccess would store the access mode and the owner's group and user id. A system with a more complicated access control system may store variable access control lists in a DCIAccess structure.

The degree of access control is entirely up to the implementation of the DCI Server. Some implementations may choose for performance reasons to support absolutely no access control. These implementations would not bother to store or check access control information. A higher level of access control may store and check access structures only at the class level. The most pervasive implementations would store a DCIAccess structure at both the class and instance levels. There is no access control at the metric datum identifier level.

Highly secure implementations may go further and layer the DCI name space on existing, secure file systems in order to conserve mechanism and provide complete mandatory and discretionary access control. Again, the choice of how much access control is entirely up to the implementation and should be documented locally.

DCI Name Space Attribute Structures

The purpose of name space attributes is to, as much as possible, allow the information stored in the name space to be self describing. These descriptions are registered by the metrics provider when adding metric classes and instances. The objects in the DCI namespace that must be described to a consumer are metric classes, instantiations of those classes (instances), and the characteristics of the data associated with each individual metric.

The attribute structures are kept separate from the data itself for performance reasons. It is expected that many DCI applications will be reading the same data multiple times so it makes sense to read the invariant information once, put it aside, and then read the changing data as much as the application requires.

There are two main attribute structures:

DCIClassAttr

Describes the attributes of an entire class. This includes some flags, a label, and implementation defined access control information.

The metric class attributes also describes the characteristics of the data associated with each metric datum contained in the class definition. Two substructures are employed for this purpose: the DCIDataAttr substructure describes the characteristics of metric datums that correspond to polled metrics; the DCIEventAttr substructure describes the characteristics of metric datums that correspond to events.

In particular, the DCIDataAttr substructure describes the datum id, the data type, the data units, and a label for each metric. Further, since most DCI routines return entire instantiated classes (which contain the data for all polled metrics in each instance), the DCIDataAttr substructure also indicates an offset within an entire return structure at which each individual polled metric's data can be directly located.

For events, the DCIEventAttr substructure describes the datum id, and the label. In addition, events can return additional data (for example, an event associated with a timer interrupt could pass the current value of the program counter; such information could be postprocessed to obtain a profile of application (or system) behaviour). Each event can have several pieces of additional data returned. The characteristics of such event data is described through the inclusion in the DCIEventAttr substructure of one DCIEventDataAttr substructure for each such piece of data to be returned when the event actually occurs. These event specific structures are described in Events and Event Data Attributes .

The number and type of instance levels with which this class is to be instantiated is also described in this attribute structure (for example, is this a per-thread class, a per-processor and per-disk class, etc.).

The DCIClassAttr structure can be extended with implementation specific information (termed, local extensions). One possible use for this optional section is a text formatting string for displaying class information.

DCIClassAttr structures are created by metric providers, and registered with the DCI Server at class registration time.

The DCIClassAttr structure for a particular metric class can be obtained with the DCI call dciGetClassAttributes().

Details of the DCIClassAttr structure are presented in DCIClassAttr .

DCIInstAttr

Describes the attributes for a specific instantiation of a class (an instance). This descriptive data includes the instance label, and implementation defined access control information. As with the metric class attribute structure, the instance attribute structure is extensible with an implementation specific (optional) extension.

DCIInstAttr structures are created by metric providers at instance registration time; they are included with the structure describing the instance method.

The DCIInstAttr structure for a particular instance can be obtained with the DCI call dciGetInstAttributes(). Details of the DCIInstAttr structure are presented in DCIInstAttr .

DCIClassAttr

The DCIClassAttr structure describes the attributes of a class. These class attributes are set by the provider of a class in the call to dciRegister() that registers the class and cannot be changed unless the class is unregistered with the dciUnregister() call. They may be retrieved by any consumer with the proper access rights using the dciGetClassAttributes() function.

The DCIClassAttr structure provides a label for the class, defines access control information for the class, describes every individual metric supported by the class, and describes the structure of the class's instance space. It also provides for local extensions to the class attributes structure. Several of the fields contained in the following definition have variable size.

typedef struct DCIClassAttr { UMAUint4 size; UMAUint4 flags; UMAVarLenDescr access; UMAVarLenDescr method; UMAVarLenDescr label; UMAArrayDescr instLevel; UMAVarArrayDescr dataAttr; UMAVarArrayDescr eventAttr; UMAElementDescr extensions; UMAVarLenData data; } DCIClassAttr;

The usage of the structure elements is as follows:

size
The total number of contiguous bytes of storage in the structure and all its associated variable length data, and must be a multiple of 4.

flags
One or more bit mapped flags with the following possible values:

DCI_ENABLED

This class is enabled and available for use. Absence of this flag means the class is disabled.

DCI_NOTIMPLEMENTED

This class is unimplemented.

DCI_NOTAPPLICABLE

This class is not applicable to the measured system and hence not available.

DCI_OBSOLETE

This class is being phased out and is not available.

DCI_PROVIDER_INSTANCE

The provider for this class does not register instances with the DCI Server. When a list of instance is requested by a consumer, the Server must request that list directly from the provider using the class method. If this flag is set, it is an error not to specify a class method also.

DCI_PERSISTENT_CLASS

The class should not be removed from the namespace (that is, unregistered) when the process that registered this class terminates (for example, issues the exit() system call). (See Operating System Interaction , "Operating System Interaction" for a discussion of persistence.)

DCI_POSSIBLEINVALIDDATA

This may return invalid data for some metrics for some instances. The application must check the DCI_INVALIDDATUMID metric for a list of other class metrics which are not valid.

access
Descriptor to the initial access control information for the class.

method
Descriptor to a DCIMethod structure for a class method. If the size of this structure is zero, then there is no class method.

label
Descriptor for a variable length ASCII and internationalised text label describing this class. If no label is desired, this must still contain a valid zero length string.

instLevel
Descriptor for a variable length DCIInstLevel structure that describes each instance present in this class.

dataAttr
Descriptor for an array of variable length DCIDataAttr structures, each representing an polled metric supported by this class.

eventAttr
Descriptor for an array of variable length DCIEventAttr structures, each representing an event metric defined in this class.

extensions
Descriptor for a variable length implementation specific block of class information.

data
Data section for all variable length information in this structure.

The relationship between the various fields in this data structure is illustrated in the DCIClassAttr diagram in DCIClassAttr Diagram .

Figure: DCIClassAttr Diagram
DCILabel
The label attributes structure contains two forms of the label. The first is a null terminated ASCII string and the second is an internationalised description. Both variable sized fields must be padded out to a four byte boundary.

The DCILabel structure is:

typedef struct DCILabel{ UMAUint4 size; UMAVarLenDescr ascii; UMAElementDescr i18n; UMAVarLenData data; } DCILabel;

The usage of the structure elements is as follows:

size
Total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

ascii
Descriptor for the variable length UMATextString for the ASCII label.

i18n
Descriptor for the variable length data for the internationalised description.

data
Data of DCIlabel for ascii and i18n.

The internationalised label indicated with the i18n descriptor is optional, and the internal structure (of the variable length contents) is unspecified because of the wide range of structures used to describe internationalised text. A typical example of the contents of the i18n label would be the name of a message catalogue and the index number of a message in that catalog.

There are some important points about DCILabel. One is that once a metric class, instance or datum has been labeled then the metric provider cannot relabel it unless the metric has been completely unregistered. Unregistering a metric class or instance can be detected by consumers. See the dciOpen() and dciClose() routine descriptions for how this is done.

In order for applications to search the name space using a semantically meaningful label (rather than the metric identifier), these labels should be unique, that is:

This ability to search the name space by label implies that providers must have registered a label with each name space entity (metric class, metric instance, metric datum), and that these labels should obey the uniqueness criteria outlined above. Maintaining unique labels is the responsibility of the entity that registers the class or adds a new instance. No DCI library function will return an error status if the label is not unique.

The following characters are reserved and should not be used in the ascii component of the DCILabel:

! (exclamation) @ (at sign) # (hash, pound sign) $ (dollar sign) % (percent) ^ (caret) & (ampersand) * (asterisk) (,) (parentheses) [,] (square brackets) {,} (braces) | (vertical bar) , (comma) . (period) ' (single quote) " (double quote) ' (back tick) : (colon) ; (semicolon)  ... (any non printing character, except " " (blank))
This reservation allows implementers to record meta-information in labels associated with datumIds, Class Attributes and Instance Attributes.
DCIInstLevel
The DCIInstLevel structure is used in an instantiated DCI class attributes structure to describe each instance level. This structure allows classes to have multiple, self described instance levels. For example, multilevel instances can be used to categorise metrics as "per-processor, per-disk I/O metrics" in a multiprocessor system with asymmetric I/O where disk drives are partitioned between processors.

The DCIInstLevel structure is shown in DCIClassAttr Diagram .

typedef struct DCIInstLevel { UMADataType type; UMAInstTagType itype; UMAUint4 size; } DCIInstLevel;

The usage of the structure elements is as follows:

type
Type of the instance level value.

itype
Instance type.

size
Size of the instance level value in bytes.

Each instance level has an instance type (itype) and an instance value type (type) associated with it. Note that different classes can be instantiated by different types of instances. For example, consider a class having a 2 level instantiation: per-processor/per-device statistics. In this example, the class is instantiated by processor id, and by device id. There would be two DCIInstLevel structures associated with this class. The processor id instance level has a particular instance type (itype) associated with it (UMA_PROCESSOR); its instance value type (type) might be UMA_UINT4 (indicating that a four byte unsigned integer is used to record a specific processor id). The device id instance level has a different instance type (itype) associated with it (for example, UMA_DEVICE); its instance value type (type) might be UMA_UINT8 (indicating that an eight byte unsigned integer is used to record a specific device number).

Instance types facilitate correct class-to-class navigation. In cases where several classes share a common instance representation (say, one instance level is the processor number, with itype UMA_PROCESSOR in each of the related classes), it is extremely useful to find the correlated metrics in each class. This can only be done if each instance representation in the system is identical for all relevant classes. For example, for two different classes which produce information per processor and have an itype of UMA_PROCESSOR, the numerical value for "Processor #2" must be identical.

UMAInstTagTypes are shown in The UMAInstTagType Enumeration , and enumerated in the <uma.h> file described in Part 2 of this publication. UMADataTypes are shown in UMADataType Values , and enumerated explicitly in the <uma.h> file in Part 2 of this publication.


Instance Type Comment
UMA_SINGLEINST a single instance of value '0' exists
UMA_WORKINFO UMA_WORKINFO enumeration
UMA_WORKID data associated with DCI_WORKINFO
UMA_MSG_QUEUE  
UMA_SEMAPHORE semaphore handle
UMA_SHR_SEGMENT shared segment handle
UMA_PROCESSOR processor number
UMA_FSGROUP  
UMA_MOUNTPOINT  
UMA_INODE inode number
UMA_DISKID disk device number
UMA_BUCKET_NO an index into a histogram
UMA_DISKPARTITION  
UMA_ACCESS_PORT  
UMA_DEVICE generic device number
UMA_KERNEL_TABLES  
UMA_CHANNEL channel number
UMA_IOP I/O processor number
UMA_PATH  
UMA_SYSCALL system call number
UMA_ENUMERATION  
UMA_STREAMS  
UMA_CONTROLLERID controller number
UMA_SCHED_CLASS scheduling class type
UMA_LOGICALVOL logical volume identifier
UMA_REMOTE_FSTYPES  
UMA_IPADDR IP address
UMA_FILESERVER_COMMAND file server command
UMA_FILECLIENT_COMMAND client command to a file server
UMA_SERVER_COMMAND command to DCI server
UMA_CLIENT_COMMAND command issued by DCI client
UMA_MEMOBJECT_ID a memory object identifier


Table: The UMAInstTagType Enumeration

Note that there is a special kind of instance type called UMA_SINGLEINST. This is the instance level type used by a provider registering a class known to have only a single instance. Such classes typically include metrics of a global (or system-wide) nature: for example, refer to the global physical I/O counters class in the Data Pool Definitions (DPD) specification.

Also included is the specific size of the identifier for this particular instance level. The purpose of the DCIInstLevel size field is to indicate the specific size of each level, in a multiple level instance specification. In the above example, processor ids require 4 bytes and device numbers require 8. The DCIInstanceId structure instances.size field would be 12 (the sum of the size of each level in a multilevel instance). The DCIInstLevel size field would be 4 for the processor instance level, and 8 for the device instance level in this class's DCIClassAttr structure.

DCIDataAttr
The DCIDataAttr structure is used to describe an individual polled metric. It is used as an array field of the DCIClassAttr structure which is used as an argument to dciRegister() when the class is registered. The DCIDataAttr structure is defined as follows:
typedef struct DCIDataAttr { UMAUint4 size; DCIDatumId datumId; UMADataType type; UMAUnit units; UMAUint4 flags; UMAUint4 offset; UMAVarLenDescr label; UMAVarLenData data; } DCIDataAttr;

The usage of the structure elements is as follows:

size
This is the total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

datumId
The datum identifier for this metric which must be unique within the class that defines it. It must be in the range 1 to 2^32-2, since 0 is a delimiter value and 2^32-1 is the wildcard value. Each polled metric datumId must be distinct from all other datumIDs in the same class, including those for events.

type
The datatype for this metric. This describes the representation of data as enumerated in UMADataType Values .

units
For data that expresses a count or time, units expresses more information about the quality of the data; for example, the metric could be a count of pages, or a count of disks. For some types of metrics (such as text strings), units does not give additional information, and UMA_NOUNITS may be specified. In the case that type is UMA_DERIVED, the units field represents the actual derived data metric (see Derived Data Units ). Size Units , Time Units , System Abstraction Count Units and Hardware Activity Count Units represent various associated units values. This is the units used to describe this polled metric.

flags
This describes other characteristics of the metric ID, in terms of what method operations the provider supports on the metric. See DCI Server/Provider Communication for more information on method operations and definitions of the DCI_OP_ flags. In particular, it should be set to the union of one or more of the following values:

DCI_QUERYABLE

The metric is queryable using the DCI_OP_GETDATA operation.

DCI_SETTABLE

The metric is settable using the DCI_OP_SETDATA operation.

DCI_RESERVABLE

The metric is reservable using the DCI_OP_RESERVEDATA operation, and releasable using the DCI_OP_RELEASEDATA operation.

offset
When polled metric data is returned as a result of being specified using a wildcard as the datumId, all the data within a single class is returned in a single block. This field is the offset into that block where this polled metric starts.

label
Descriptor for a variable length ASCII and internationalised text label describing this polled metric. If no label is desired, this must still contain a valid zero length string.

data
Data section for all variable length information in this structure.

DCIEventAttr
The DCIEventAttr structure is used to describe an individual event metric. It is used as an array field of the DCIClassAttr structure which is used as an argument to dciRegister() when the class is registered. The DCIEventAttr structure is defined as follows:
typedef struct DCIEventAttr { UMAUint4 size; DCIDatumId datumId; UMAVarLenDescr label; UMAVarArrayDescr eventDataAttr; UMAVarLenData data; } DCIEventAttr;

The usage of the structure elements is as follows:

size
This is the total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

datumId
The datum identifier for this metric which must be unique within the class that defines it. It must be in the range 1 to 2^32-2, since 0 is a delimiter value and 2^32-1 is the wildcard value. Each event datumId must be distinct from all other datumIDs in the same class, including those for polled metrics.

label
Descriptor for a variable length ASCII and internationalised text label describing this event. If no label is desired, this must still contain a valid zero length string.

eventDataAttr

This is a descriptor for the event data that correspond to this event. The descriptor points to an array of DCIEventDataAttr structures, each of which specifies the format of one piece of data that is attached to an event metric by the provider when it is generated. See Events and Event Data Attributes for information on how this relates to the event data itself.

data
Data section for all variable length information in this structure.

DCIInstAttr

Instance attributes are considerably simpler than metric class attributes. The DCIInstAttr structure can be used to discover a particular instance's label and access control information. There is also a provision for local extensions to this structure. The DCIInstAttr structure definition is:
typedef struct DCIInstAttr { UMAUint4 size; UMAUint4 flags; UMAVarLenDescr access; UMAElementDescr extension; UMAVarLenDescr label; UMAVarLenData data; } DCIInstAttr;

The usage of the structure elements is as follows:

size
This is the total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

flags
Special instance state flags.

access
Descriptor for the DCIAccess access control structure for this instance.

extension
Descriptor for variable length extension associated with this instance.

label
Descriptor for variable length DCILabel structure associated with this instance.

data
The actual variable length data (DCIAccess, DCILabel and extensions) associated with this instance.

The flags field contains a sequence of bit mapped flags. The values of these flags are given in the <dci.h> file. Their descriptions are below:

DCI_PERSISTENT_INSTANCE

The instance should not be removed from the namespace (that is, unregistered) when the process that registered this instance terminates (for example, issues the exit() system call). (See Operating System Interaction , "Operating System Interaction" for a discussion of persistence.)

Events and Event Data Attributes

The only information required for some events is simply that they have occurred. However, there is a wide range of applications for events that have a need for associated data to describe additional characteristics of the event. The event related data structures in the DCI attempt to be flexible enough to match this requirements range without imposing undue burden upon the simple cases.

There are two specialised structures used only with events. The first structure, the DCIEventDataAttr, is used in the DCIEventAttr to describe event data to be delivered along the event when it occurs. The second, DCIEvent, is the structure used when an event occurs to describe the event itself, and pass along any associated event data.

Note that event metric attributes are separated from event data to improve event delivery performance by decreasing the size of the transmitted structures; the nonvariant attributes may be fetched only once and saved for future reference by the MAP.

DCIEventDataAttr
The DCIEventDataAttr structure is used in the DCIEventAttr structure. For example, if a provider needs to pass along three additional pieces of data whenever an event occurs, the count field of the eventDataAttr structure (in the DCIEventAttr structure, see DCIEventAttr and DCIEventDataAttr Structures ) is set to three, and there will be three of the following structures in the variable length section of the DCIEventAttr structure.
typedef struct DCIEventDataAttr { UMAUint4 size UMADataType type; UMAUnit units; UMAUint4 offset; UMAVarLenDescr label; UMAVarLenData data; } DCIEventDataAttr;

The usage of the structure elements is as follows:

size
This is the total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

type
This is the type of this event datum. This type implies either a fixed number or a variable number of bytes in the case of UMA_TEXTSTRING or UMA_OCTETSTRING.

units
This is the units of this event datum.

offset
This is the offset into the DCIEvent structure where this event is to be found.

label
Descriptor for a variable length ASCII and internationalized text label describing this event datum. If no label is desired, this must still contain a valid zero length string.

data
Data section for all variable length information in this structure.

There are several things to note about this structure. First is the fact that it does not describe a DCI metric. There is no mechanism to automatically retrieve the value of selected metrics whenever an event is reported. This structure describes raw data that will be delivered directly by a provider to the DCI Server when the provider makes a dciPostEvent() call.

Second, if the provider does not plan to transmit event data for an event, then the count field of the eventDataAttr structure (in the DCIEventAttr structure, see DCIEventAttr and DCIEventDataAttr Structures ) is zero, and no DCIEventDataAttr structures will be present. A consumer can check the structure of the event data by using the dciGetClassAttributes() to retrieve this structure for any event metrics in the class.

DCIEvent
The DCIEvent structure describes the occurrence of an event itself. This is the structure that a consumer receives from dciWaitEvent(). Part of the information in this structure is furnished when an event is reported using dciPostEvent(), and part is furnished by the DCI Server itself, as follows.

Consumers have control over the format of output events; this control is expressed through the content of the datumId used at the time of the dciOpen(). The datumId is logically divided into 3 pieces: 12 bits of user specified flags, 12 bits of user specified event id and 8 bits of datum id. [Recall that the datumId for polled metrics is partitioned to support derived metrics. Note that for both polled and event metrics, the low order 8 bits are reserved for the unique datum id.] The flags determine the format and content of the returned data for this event:

DCI_EVENTHDR

An event header is to be included in the posted event structure

DCI_EVENTHDRCLASSID

A class id is to be included in the posted event structure

DCI_EVENTHDRINSTANCEID

An instance id is to be included in the posted event structure

DCI_EVENTHDRTIMESTAMP

A time stamp of the type UMATimeSpec is to be included in the posted event structure

DCI_EVENTHDRVENDORTIMESTAMP

A timestamp of an implementation defined format is included in the posted event structure

DCI_EVENTHDRCOMPTIMESTAMP

A compressed timestamp is to be included in the posted event structure

DCI_EVENTHDRSTREAMID

An event stream identifier is to be included in the posted event structure

DCI_EVENTHDRDATA

The event data is to be included in the event structure

Values for these flags are set by the provider at dciRegister() time to indicate the providers capability with respect to reporting data for the corresponding event. At dciOpen() time the DCI Server will use the provider's flags as a mask to determine the extent to which it can satisfy the consumer's request for event format and content. (For example, if the provider registered events indicating no DCI_EVENTHDR, then a consumer's request for event headers will be denied.)

These flags are also returned by the DCI Server as part of the header associated with all returned events (assuming the consumer has requested that an event header be included as part of the returned event's data).

The event header (DCI_EVENTHDR) is optional. If it is not present, this indicates that the structure of the event data is implementation defined. If it is present, then the event data is defined as follows:

For events containing an eventHeader, the event structure is defined as follows:

typedef struct DCIEvent { UMAUint4 eventHeader; UMAVarLenData data; } DCIEvent;

Note that the structure of events lacking an event header is implementation defined.

The usage of the structure elements is as follows:

eventHeader
The event header is a variable length structure. The first word consists of 12 bits of flags, 12 bits of event id and 8 bits of size. If the size byte contains 0xff, then the event's size exceeds 256 bytes and a subsequent 32 bit word contains the actual size of the event.

data
Data section for all variable length information in this structure. This includes any data mandated by the presence of the event header flags, followed by the variable length data prescribed for this event metric by its registered DCIEventDataAttr structure.

DCIEventAttr and DCIEventDataAttr Structures shows how the information in the three structures, DCIEventAttr, DCIEventDataAttr, and DCIEvent are related.


Figure: DCIEventAttr and DCIEventDataAttr Structures

(with reference to DCIEvent structure)

When a provider reports an event using the dciPostEvent() function, the DCI Server combines the information furnished by the provider with the information it provides itself to form a DCIEvent structure. The DCI Server then passes this structure to any consumers who are waiting for this event.

Data Types

The dataType field in the attributes structures describes the metric type. By examining the value of dataType one can determine the type and size of data object for the associated metric. These are necessary for correct interpretation of the data described by the attributes structure.

The following table lists the symbolic name for the UMA data type value, the related UMA data type, the size of the data type in bytes, and a brief description. It is important to note that the UMA data type values are simply a flag indicating the type and the UMA data type column are the types themselves. So a UMA_INT4 value in dataType states that a UMAInt4, or a four byte integer, is being used for a particular metric.


UMA Data Type Value UMA Data Type Size in Bytes Description
UMA_INT4 UMAInt4 4 four byte integer
UMA_INT8 UMAInt8 8 eight byte integer
UMA_UINT4 UMAUint4 4 four byte unsigned integer
UMA_UINT8 UMAUint8 8 eight byte unsigned integer
UMA_BOOLEAN UMABoolean 4 boolean value, with
      FALSE = 0, TRUE != 0
UMA_OCTETSTRING UMAOctetString variable octet string
UMA_TEXTSTRING UMATextString variable variable length text data
UMA_TIMEVAL UMATimeVal 8 UNIX like time structure
UMA_TIMESPEC UMATimeSpec 8 time interval in nanoseconds
UMA_DERIVED - 0 data that must be derived
      from other metrics.
UMA_CLASSDATA UMAClassData variable all polled metrics
      within the same class.


Table: UMADataType Values
The first five data types listed in UMADataType Values consist of signed and unsigned integers of different sizes. The next four entries describe different structures. In all cases, the size of a data object is padded to a four-byte boundary. (The reason for this restriction is so that structures built from a combination of these data types can always be four-byte aligned. When performing unaligned accesses, such as reading a four-byte integer at an address having the least significant bit set, some system architectures suffer serious performance degradation, or are simply unable to perform the access.)

Three variable length data types are supported: UMAOctetString, UMATextString and UMAClassData. The data structures for the first two types are identical: a variable length byte array called "string" and a "size" field includes the size of the entire structure along with the variable length data and enough padding ensure that the "size" field is always a multiple of 4 bytes in size. While the UMATextString data type is composed of a null-terminated array of bytes, the UMAOctetString may include embedded nulls or multibyte characters. This interpretation of the UMAOctetString data is beyond the scope of this specification.

typedef struct UMAString { UMAUint4 size; /* size of entire structure */ char string[1] /* variable length text string */ } UMATextString, UMAOctetString

The data structure for the UMAClassData depends on the context in which it appears. Its purpose is to compactly identify the contents of the Final Data event associated with a class. Providers for classes that support final data events must return final values for all polled metrics in that class prior to instance termination. The definition of UMAClassData simplifies the registration of such a Final Data event by requiring that the DCIEventDataAttr for that event declare the type of data as UMAClassData. [This avoids requiring repetition of all attributes for all polled metrics explicitly in the DCIEventDataAttr structure.] The Final Data event for a particular class would contain a single Event Data Attribute having type UMAClassData, units UMA_NOUNITS, and offset 0.

The UMATimeVal and UMATimeSpec structures specify a time interval in terms of a number of seconds and a number of fractional seconds: in the case of UMATimeVal the fractional seconds are measured in microseconds and in the case of UMATimeSpec the fractional seconds are measured in nanoseconds. These time interval structures are used for timeout parameters as well as timestamps; in the latter case, the number of seconds is given relative to the date Jan 1, 1970 at 12 am (also known as the Epoch). These time intervals are malformed if the number of seconds is negative or if the fractional number of seconds is negative or if the total fractional component is greater than or equal to 1 second.

The UMA_DERIVED data type is used to encode relationships between datums within a single class. When used as the type of a particular DCIDatumId, the corresponding UMAUnit field should be examined to determine the specific interrelationship that is encoded. See Measurement Units for further discussion of the supported encodings.

Note that a data type of UMA_DERIVED indicates that the associated metric is not available directly, but must be derived from other metrics using the encoded interrelationship. Such a derived metric cannot be explicitly specified for data retrieval, but must be part of a whole class of retrieved data (i.e., the class has been fetched with the wildcarded datumId). The values of derived metrics must be obtained by the application; there is no DCI API support for doing so directly.

Measurement Units

The attributes structure unit field of typedef UMAUnit is used to indicate what the metric is measuring (or, in the case of derived metrics, how the metric is related to other metrics). For non-derived metrics, the purpose of the unit field is to provide additional descriptive information about the properties of the metric to the measurement application (the DCI consumer). For example, for metrics that report memory related size information, the unit field indicates whether the value returned is expressed in bytes, kilobytes, megabytes, etc. For metrics that indicate time values, the unit field indicates whether the value returned is in seconds, milliseconds, microseconds, nanoseconds, etc.

The DCI provides for five distinct unit types: size, time, count, info and derived. (There is an additional unit type: UMA_NOUNITS, used for metrics for which the units designation is not meaningful.) Within each unit type there are many values; these are enumerated below in a series of tables.


Size
UMA_BYTES bytes
UMA_KBYTES kilobytes
UMA_MBYTES megabytes
UMA_GBYTES gigabytes
UMA_TBYTES terabytes


Table: Size Units


Time
UMA_SECS seconds
UMA_MILLISECS milliseconds
UMA_MICROSECS microseconds
UMA_NANOSECS nanoseconds
UMA_PICOSECS picoseconds
UMA_TICKS machine clock ticks


Table: Time Units

There are a large number of object types that can be counted and new operating systems can always invent new types of objects. The purpose here is to identify some of the commonly measured objects and establish some unit field values for these. The types of objects being counted can be divided naturally into two types: software objects or "system abstractions" and hardware objects.


Counts of System Abstractions
UMA_COUNT an unspecified count
UMA_EVENT an unspecified event
UMA_PAGES memory pages
UMA_BLOCKS disk blocks
UMA_CHARACTERS characters
UMA_QLENGTH queue length
UMA_PROCESSES processes
UMA_TASKS tasks
UMA_THREADS threads
UMA_JOBS jobs
UMA_USERS users
UMA_TRANSACTIONS transactions
UMA_MESSAGES messages
UMA_SESSIONS sessions
UMA_STREAMSMODULES streams modules
UMA_STREAMSHEADS streams heads
UMA_STREAMSMSGS message blocks
UMA_PACKETS packets
UMA_INODES inodes
UMA_FILES files
UMA_FILESYSTEMS file systems


Table: System Abstraction Count Units


Counts of Hardware Activity or Objects
UMA_READS reads
UMA_WRITES writes
UMA_SEEKS seeks
UMA_IOCTLS ioctls
UMA_CONNECTIONS connections
UMA_RETRIES retries
UMA_MOUNTS mounts
UMA_REWINDS rewinds
UMA_POSITIONINGS positionings
UMA_MARKS tape marks
UMA_PORTS ports
UMA_PROCESSORS processors
UMA_DISKS disks
UMA_NETS networks
UMA_SLINES serial lines
UMA_BUSSES busses
UMA_CHANNELS I/O channels


Table: Hardware Activity Count Units

Two of the above counts, UMA_COUNT and UMA_EVENT, can be used for undefined counts and events. There will, of course, be objects that are not listed here or vendor specific objects. A value of UMA_NOUNITS indicates that units are not applicable to this metric. To handle future and vendor expansion this specification reserves the numerical range 0-2^16 for predefined DCI unit values. The rest of unit's numerical range is available for extension.

Refer to the <uma.h> file at the end of this specification for a mapping of DCI units to a specific enumerated type.

For derived metrics (i.e., those whose dataType attributes field is recorded as UMA_DERIVED), the units indicate precisely how this derived metric is related to other metrics in the class.

Inter-metric relationships are encoded explicitly in the DCIDatumId of each derived metric. For this purpose, the DCIDatumId is partitioned in the following manner:

arg1 arg2 arg3 id

Figure: DCIDatumId for Derived Metric Support
Where arg1, arg2 and arg3 are the unique (within a class) last 8 bits of the DCIDatumIds of the other metrics in the class to which the derived metric is related.

The following types of relationships can be expressed:


Manifest Constant Argument Definition Formula
UMA_DERIVED_SUM2 arg1 = a value arg1 + arg2
  arg2 = a value  
UMA_DERIVED_SUM3 arg1 = a value arg1 + arg2 + arg3
  arg2 = a value  
  arg3 = a value  
UMA_DERIVED_DIFFERENCE arg1 = a value arg1 - arg2
  arg2 = a value  
UMA_DERIVED_AVERAGE arg1 = a value arg1 / arg2
  arg2 = a value  
UMA_DERIVED_PERCENT arg1 = a value arg1 / (arg1 + arg2)
  arg2 = a value  
UMA_DERIVED_PRODUCT arg1 = a value arg1 * arg2
  arg2 = a value  
UMA_DERIVED_VARIANCE arg1 = a count (arg3/arg1)-(arg2)^2/arg1
  arg2 = a sum  
  arg3 = a sum of squares  


Table: Derived Data Units
(Note that a definition of standard deviation is not given since standard deviation is derived directly from variance, and does not depend on relationships between other metrics.)

Finally, for certain metrics, the units designation is not meaningful. In these cases, the UMA_NOUNITS value is selected.


For situations in which "units" do not apply
UMA_NOUNITS indicates units do not apply to this metric


Table: Metrics with no Units

Invalid Data

There are cases where a whole class of data cannot be retrieved for all instances, such as the "byteswritten" count for ReadOnly devices, or the size of unmounted disk partitions. In these cases, rather than splinter the class to contain only the valid metrics, an additional data structure can be returned with the fetched data and the application can check whether the data it seeks is valid or not. As a performance optimization, the application need only check each data metric for validity if a hint bit is set in the class attributes flags (DCI_POSSIBLEINVALIDDATA) and the informational return status DCI_INVALIDDATAPRESENT is received. In the case of dciWaitEvent(), there is no way to return DCI_INVALIDDATAPRESENT and the measurement application (consumer) is obligated to examine each piece of data for whole classes that have the DCI_POSSIBLEINVALIDDATA attribute flag set.

A special datumId (DCI_INVALIDDATUMID) is reserved for use in classes which need to express partial class data for some instances. The dciRegister() will fail if a class is specified with DCI_POSSIBLEINVALIDDATA and a DCI_INVALIDDATUMID was not. This associated data for this datumId is a variable length DCIInvalidData structure (since this structure is variable length, the data offset for the datumId represents an indirect offset to the actual structure). This structure is an array of DCIDatumIds which are not valid in the presented class data for this instance. If an invalid metric is explicitly referenced (using dciGetData() or dciSetData() with a non-wildcarded DCIDatumId) then the error DCI_INVALIDDATA will be generated. If this class can produce invalid data, but all metrics are valid for this instance, the offset for the DCIInvalidData structure is 0 and should not be referenced.

If a particular metric is marked as invalid, then its value should not be referenced by the application. Such invalid metrics may not be settable with dciSetData(), depending upon the provider.

For example, if a class of data is returned with the informational status DCI_INVALIDDATAPRESENT, then the invalid list must be checked before referencing a metric in the returned list. One must obtain the UMAUint4 offset for the DCI_INVALIDDATUMID; if the offset is zero, then no validity data needs to be consulted (although in this case, the implementation should have not generated the DCI_INVALIDDATAPRESENT status). If the offset is non-zero, then it is added to the base address of the returned data and cast to a DCIInvalidData structure pointer. Use the macro *dciinvaliddatacount* to determine how many invalid metrics exist and the macro *dciinvaliddatumid* to check each DCIDatumId in the list.

DCI Server/Provider Communication

The DCI Server needs to communicate with a provider for several purposes. When a dciGetData() or dciSetData() request is made, the DCI Server must forward the request to the appropriate provider and then return the appropriate data to the consumer that requested it. When a consumer calls dciConfigure() to configure a metric, the DCI Server must ask the provider to perform the configuration operation. Finally, if a provider has specified DCI_PROVIDER_INSTANCE in the flags field of the DCIClassAttr, then that provider is saying that it will never make any calls to dciAddInstance() or dciRemoveInstance(). So whenever the DCI Server needs to find out what instances are available, it must explicitly ask the provider to find out what instances currently exist. Typically, a DCI Server will need this information in order to respond to a dciListInstanceId() or dciGetInstAttributes() request from a consumer. One reason a provider may decide to do this is that the instance space of a class is changing very rapidly and the overhead of making frequent calls to dciAddInstance() and dciRemoveInstance() is deemed unacceptable to system performance. Methods are the mechanism that allow a provider to instruct the DCI Server exactly how to perform this communication.

The DCI specifies four method types, as outlined in the following table, which are explained in detail in further sections.


Method Explanation
DCI_WAIT Provider blocks waiting for requests
DCI_STORE DCI Server stores posted data
DCI_ADDRESS DCI Server retrieves data from provider's address space
DCI_CALLBACK DCI Server requests data by calling a routine in
  provider's address space


Table: Method Types

All DCI implementations must provide at least the DCI_WAIT method for portability, but may choose to either implement or not implement the other three methods since these may depend on features that may not be available on some operating systems. Also, some methods available to user space metric providers may not be available to operating system metric providers on the same machine. For example, it doesn't make sense to have a device driver block waiting for a metrics request. An implementation may also freely specify additional method types as well. The DCI Server returns an error if a provider attempts to specify an inappropriate or unavailable method.

Methods can be specified on a class basis using dciRegister() when the class is registered, or for a specific instance using dciAddInstance() when the instance is added. For a DCI_PROVIDER_INSTANCE class, a provider may only (and must) specify a class method, since instance data is managed by the provider. In all other cases, either an instance method, a class method, or both may be specified.

A method, either a class method or an instance method, may support several of the different types of requests that a DCI Server may make to a provider. The type of request is embodied in one of seven bitmap operation codes.


Operation Type Corresponding Consumer API Call
DCI_OP_GETDATA dciGetData()
DCI_OP_CONFIGURE dciConfigure()
DCI_OP_LISTINSTANCES dciListInstanceId() for
  DCI_PROVIDER_INSTANCE class
DCI_OP_GETINSTATTR dciGetInstAttributes() for
  DCI_PROVIDER_INSTANCE class
DCI_OP_SETDATA dciSetData()
DCI_OP_RESERVEDATA dciSetData()
DCI_OP_RELEASEDATA dciSetData()


Table: Types of Operations

When the DCI Server executes a method, it indicates which operation it is requesting. If the provider registered both a class method and an instance method, the DCI Server tries the instance method first. If that method fails it retries the operation using the class method. If any of the methods fail, the DCI Server returns an error to the requesting consumer.

The provider responds to the request with a dciPostData() call, which also indicates to which type of operation it is responding. All <specified> methods, except DCI_ADDRESS, use dciPostData() to deliver the metrics and other data to the DCI Server.

The DCIMethod structure is used to identify a method. It can describe a class method if set in the DCIClassAttr structure, or can describe an instance method if used as an argument to dciAddInstance(). The DCI Server can then use the information in this structure to determine what method to use to satisfy requests from a consumer.

typedef struct DCIMethod { UMAUint4 size; DCIMethodType type; UMAElementDescr method; UMAVarLenData data; } DCIMethod;

The usage of the structure elements is as follows:

size
This is the total number of contiguous bytes of storage in the structure and all its associated variable length data, which must be a multiple of 4.

type
The method type which indicates how data will be retrieved, and is one of DCI_WAIT, DCI_STORE, DCI_ADDRESS, or DCI_CALLBACK.

method
Descriptor for variable length method data.

data
Data for the variable length attributes and method data.

Not every method type can support every operation. Although described in detail below, Valid Operations for Each Method Type summarises which methods may support which operations. Attempting to specify an unsupported operation in a DCIMethod argument results in an error code of DCI_METHODOPUNAVAILABLE.


  Method Types
Method Operations _
  DCI_WAIT DCI_STORE DCI_ADDRESS DCI_CALLBACK
DCI_OP_GETDATA yes yes yes yes
DCI_OP_CONFIGURE yes no no yes
DCI_OP_LISTINSTANCES yes no no yes
DCI_OP_GETINSTATTR yes no no yes
DCI_OP_SETDATA yes yes yes yes
DCI_OP_RESERVEDATA yes yes yes yes
DCI_OP_RELEASEDATA yes yes yes yes


Table: Valid Operations for Each Method Type

The following sections describe the use of provider operations, dciPostData() and methods in detail.

Provider Operations for Polled Metrics
In most cases all data transferred from the DCI Server to the provider, or vice versa, are encoded in a DCIReturn structure. The exception is DCI_ADDRESS, in which case the DCI Server retrieves the requested data itself. To clarify the role of the metric identifiers and corresponding data for each operation, the DCIReturn structure in both directions are described in detail for each operation. First some behaviour identical to all methods is described.

Class identifiers can never be wildcarded at the provider level. So, wildcards are not permitted in the class identifiers in any of the DCIReturn structures passed between DCI Server and provider. Datum identifiers can always be wildcarded, although in some methods the datum identifiers are ignored. For DCI_PROVIDER_INSTANCE classes the instance identifier can be wildcarded in any of the operations. For all other classes the instance identifier cannot be wildcarded. Note that the DCI_OP_LISTINSTANCES and DCI_OP_GETINSTATTR operations are only used for DCI_PROVIDER_INSTANCE classes. A DCI_PROVIDER_INSTANCE class provider expands the wildcarded instance identifiers as necessary.

Since the data returned by the provider is located in a separate data buffer, all offsets in the return DCIReturn structure are relative to the start of this data buffer.

DCI_OP_GETDATA

The DCIReturn structure as it is received by the provider contains fully specified metric identifiers. Summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately with offsets to the actual data, which conforms to the previously registered attributes structure. In the case of a datum identifier wildcard, the corresponding data section contains all data of the specified class instance, each datum with an offset as specified in the previously registered attributes structure. Summary, status and return values are significant.

DCI_OP_CONFIGURE

The DCIReturn structure as it is received by the provider contains fully specified metric identifiers with offsets to the actual data. The instance identifier may be of zero length, which means "all instances, including future ones". Each data section corresponding to a metric identifier contains DCIConfig data structure(s). Summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately with offsets to the actual data. Each data section corresponding to a metric identifier contains DCIConfig data structure(s). Summary, status and return values are significant.

The dciConfigure() manual page further defines the DCIConfig structure for both the request and reply directions of any configure operation.

DCI_OP_LISTINSTANCES

The DCIReturn structure as it is received by the provider contains metric identifiers of which the datum identifier is ignored. No data is provided and summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately. The datum identifiers are ignored. No data is provided. Summary, status and return values are significant.

DCI_OP_GETINSTATTR

The DCIReturn structure as it is received by the provider contains metric identifiers of which the datum identifier is ignored. No data is provided and summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately, and contains offsets to the actual data. The datum identifiers are ignored. Each data section corresponding to a metric identifier contains DCIInstAttr structure(s). Summary, status and return values are significant.

DCI_OP_SETDATA and DCI_OP_RESERVEDATA

The DCIReturn structure as it is received by the provider contains fully specified metric identifiers with offsets to the actual data, which conforms to the previously registered attributes structure. In the case of a datum identifier wildcard, the corresponding data section contains all data of the specified class instance(s), each datum with an offset as specified in the previously registered attributes structure. Summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately. No data is returned. Summary, status and return values are significant.

DCI_OP_RELEASEDATA

The DCIReturn structure as it is received by the provider contains fully specified metric identifiers. Summary and status values are unused.

The DCIReturn structure returned by the provider repeats or expands all metric identifiers appropriately. No data is returned. Summary, status and return values are significant.

Provider Methods for Polled Metrics

DCI_WAIT

The DCI_WAIT method indicates that the provider is planning to register its metrics and then use the dciWaitRequest() routine to wait for consumer requests for its registered metrics. For a provider to register it, the type field of the DCIMethod structure is set to DCI_WAIT. There is no method data required when registering a DCI_WAIT method. All operations are supported by this method.

For a provider to use the DCI_WAIT method, it first makes a call to dciWaitRequest() that will block until the DCI Server requests an operation on one or more of the indicated metrics. When the call returns the operation is filled in, and the DCIReturn structure contains the requested metric identifiers. If data is associated with the request in the case of a DCI_OP_SETDATA, DCI_OP_RESERVEDATA or DCI_OP_CONFIGURE, it is contained in the DCIReturn structure. The provider must answer to the request by submitting results with dciPostData().

DCI_STORE

The DCI_STORE method indicates that the provider wants to spontaneously generate polled metric data and send it to the DCI Server using dciPostData() without waiting for the DCI Server to make an explicit request. The DCI Server should independently handle requests from consumers, without interaction with the provider. The DCI Server is thus responsible for allocating storage to retain the values of these metrics and for returning appropriate errors to consumers or providers if it is unable to allocate this memory (or disk space). This method may not be used to support the DCI_OP_LISTINSTANCES, DCI_OP_GETINSTATTR, or DCI_OP_CONFIGURE operations.

When this method is used, each dciAddInstance() call, for which this method is in effect, must specify the initial values of all metrics in the class instance, by filling out the DCIReturn buffer.

If the DCI_OP_GETDATA operation on a metric is supported by the DCI_STORE method, a consumer may retrieve the current value of the metric using dciGetData(), and the provider may change it using dciPostData(). If the DCI_OP_SETDATA operation on a metric is supported by the DCI_STORE method, a consumer with proper access rights may also set the value of the polled metric using dciSetData().

DCI_ADDRESS

The DCI_ADDRESS method may be used when the provider is able to specify the location of the values of metrics in terms of a single address per metric. It may be supported by implementations on operating systems that allow the DCI Server to reach into the address space of a provider and read memory. It is an error to specify this method type to support the DCI_OP_LISTINSTANCES, DCI_OP_GETINSTATTR or DCI_OP_CONFIGURE method type.

In order to use this method type, all polled metric values for the class must exist in a single block of address space that can be copied directly into the data area of a DCIReturn structure. Each datum in the class must exist at the offset into the block that is specified in the offset field of the corresponding DCIDataAttr structure.

When the method is registered for an instance method using dciAddInstance() or a class method using dciRegister(), the data area of the DCIMethod struct contains the following struct.

struct DCIAddressMethodData { void *address; UMAUint4 size; void *sync; };

The usage of the structure elements is as follows:

address
Address of the block of memory in the provider's address space where values for the polled metrics in this class start.

size
The size of the memory block in bytes.

sync
Pointer to an implementation dependent synchronisation structure used to synchronise access to the entire block of memory pointed to by address. If this is zero, no synchronisation is performed.

When a consumer requests an operation supported by the DCI_ADDRESS method, the DCI Server goes out and directly reads or sets the current value of this metric using the sync object to synchronise access to that location.

If the address space of a provider that has registered a DCI_ADDRESS instance method becomes inaccessible to the DCI Server, for example, if the provider terminates, all instances added by that provider are implicitly removed. If a DCI_CLASS method was registered, then the class is implicitly removed.

DCI_CALLBACK

The DCI_CALLBACK method allows a provider to specify a function in its address space that the DCI Server will call to perform an operation. It may be supported by implementations on operating systems that allow the DCI Server to reach into the address space of a provider and execute code. All operations are supported by this method.

When a provider specifies this method, it supplies the DCI Server with a function that it may call to perform an operation. When the DCI Server wants to execute an operation, it calls this function with the following prototype:

DCIStatus callback( UMAUint4 operation, /* in */ DCIReturn *request /* in */ );

The usage of the structure elements is as follows:

operation

The operation being requested. Must be one of the values possible in the operation field of the DCIMethod struct.

request

Pointer to the DCIReturn structure containing all metric identifier information, and data in the case of DCI_OP_SETDATA, DCI_OP_RESERVEDATA or DCI_OP_CONFIGURE. The metric identifiers may contain wildcards for the datumId, for the instanceId in the case of a class method, but not for the classId.

When a consumer requests an operation implemented by this method, the DCI Server makes the appropriate callback. The provider must use dciPostData() to post the data requested by the operation, as it cannot be returned using the callback.

If the address space of the provider that has registered a DCI_CALLBACK method becomes inaccessible to the DCI Server, for example if the provider terminates, all instances added by that provider are implicitly removed. If a class method was registered, the class is implicitly removed.

Note that the callback routine is not a part of the DCI specification. It is provided by the provider. The routine must follow certain conventions. These are outlined below:

Description of callback behaviour

The callback routine is a prototype routine for the callback routine used in the DCI_CALLBACK method. This routine is defined by the provider using a local name and registered together with the DCI_CALLBACK method with the DCI Server, using dciRegister() or dciAddInstance(). The DCI Server will call this routine when a consumer requests the provider's metrics using dciGetData(), alters metrics using dciSetData(), lists instances with dciListInstanceId(), requests instance attributes with dciGetInstAttributes(), or configures metrics using dciConfigure().

When the DCI Server executes this callback function, it passes in the operation and the requested metrics. If data is passed it is encoded in the DCIReturn structure using offsets from the beginning of the DCIReturn buffer.

If the operation is DCI_OP_GETDATA or DCI_OP_RELEASEDATA, only metric identifiers are supplied in the DCIReturn structure. Only datum identifier wildcards are allowed, unless the class is a DCI_PROVIDER_INSTANCE class in which case instance identifier wildcards are allowed.

If the operation is DCI_OP_LISTINSTANCES, only metric identifiers are supplied in the DCIReturn structure, of which the datum identifier should be ignored. The instance identifiers can be wildcarded.

If the operation is DCI_OP_GETINSTATTR, only metric identifiers are supplied in the DCIReturn structure, of which the datum identifier should be ignored. The instance identifiers can be wildcarded.

If the operation is DCI_OP_CONFIGURE, data is supplied in the DCIReturn structure in addition to the metric identifiers. Each data section contains one or more DCIConfig structures, depending on the number of instance identifiers encoded in the corresponding metric identifier. The instance identifier can be zero length which indicated "all current and future instances". Only datum identifier wildcards are allowed, unless the class is a DCI_PROVIDER_INSTANCES class in which case instance identifier wildcards are allowed.

If the operation is DCI_OP_SETDATA or DCI_OP_RESERVEDATA, data is supplied in the DCIReturn structure in addition to the metric identifiers. This data conforms to the previously registered attributes structure. Only datum identifier wildcards are allowed, unless the class is a DCI_PROVIDER_INSTANCES class in which case instance identifier wildcards are allowed.

Return Values from callback

The callback prototype routine returns DCI_SUCCESS to the DCI Server if it successfully serviced the request. Otherwise, this routine returns one of the DCI error values to indicate the failure type.

[DCI_NOTPRESENT]

The DCI service is not available.

[DCI_NOIMPLEMENTATION]

In a DCI subset implementation, the specified routine has not been implemented.

[DCI_NOTINITIALIZED]

The DCI subsystem is not currently initialised.

[DCI_SYSERROR]

An internal error has occurred (such as a shortage of resources) that may be beyond the control of the application. A vendor-specific error code is placed in the variable errno.

[DCI_ALLOCATIONFAILURE]

The provider could not allocate memory for the return buffer which would be submitted with dciPostData().

[DCI_INVALIDARG]

One of the input arguments is invalid: a negative value was used for numIds, bufferSize is smaller than the size of a DCIReturn structure, MetricIdList was malformed, or the MethodList was malformed.

[DCI_INTERRUPTED]

The callback prototype call was interrupted by a signal and did not complete.

DCI Routine Return Status and Structures

The DCI routines have a consistent interface. An application, either a metrics provider or consumer, calls a routine with a list of metric identifiers as an argument. The DCI routine performs the request and then writes status and data into a user provided buffer or, if requested, into a buffer allocated on behalf of the user by the DCI. If the DCI allocated the status buffer, then the user is responsible for subsequently freeing the allocated memory. The return structure used for this buffer, pictured in the accompanying diagram, is the same for the different DCI routines. The diagram shows a successful return structure for a request with a list, after wildcard expansion, of "n" metrics.

A DCI routine always returns the DCIStatus type. These routines use the DCIStatus type definition to return success when the request succeeds for every metric in the expanded input metric list. In the success case, the routine DCIStatus return value is DCI_SUCCESS. A DCIStatus error or warning value is returned if the request cannot be satisfied for any metric in the list. The error status value is a summary error and may not be the same for every metric in the expanded input list. The application must traverse the DCIReturn structure to discover the status value for each metric in the expanded input list.

Figure: DCIReturn Structure Example

The return structure begins with a four byte integer that contains the total number of bytes written. The purpose of this size is to allow range checking and for quick traversal of multiple DCIReturn structures. The total size is followed by a count of the total number of expanded input list identifiers. The next field consists of a summary status word. Two timestamps follow; the first indicates the time of the start of the DCI operation; the second indicates the time of the completion. Both timestamps are (optionally) filled in by the DCI Server/server library, and only have significance for the dciGetData api call. The two timestamps may be used by a consumer to gauge the currency of the collected data; if the two timestamps are not "close enough", the DCI operation may have taken too long to complete. (If the timestamps are not "close enough", the consumer may choose to discard the data and retry the request.) Each timestamp is optional. A value of zero (0) for either timestamp indicates that the implementation does not support timestamping at the server. [Note that if the provider also chooses to provide a timestamp, it may do so by including a specific datumId in the class for that purpose.]

This header, the total size, count, status and timestamps, is followed by three arrays. The first is an array of count DCIRetval structures, one for each expanded input metric identifier. The DCIRetval structure gives the return status, an offset to a copy of the metric identifier, an offset to the output data for this request, and the size of the data returned by this request. All offsets are from the beginning of the DCIReturn structure. Note that the DCIRetval structure is a fixed size, allowing for quick traversal of the DCIRetval array.

Following the array of DCIRetval structures is a copy of the expanded input metric identifier list and the returned data buffer. The expanded metric identifier list may be either a list of DCIClassId's or DCIMetricID's. Some DCI routines, such as dciListClassId(), take metric class identifier lists as input. Others, such as dciListInstanceId(), take full metric identifiers, class plus instance, as input. Applications acquire offsets into these buffers by traversing the DCIRetval array.

The DCIReturn, DCIRetval, and DCIStatus structures and type definitions are defined as follows:

typedef struct DCIRetval { DCIStatus status; /* status for input argument */ UMAUint4 metricOffset; /* offset to input id value */ UMAUint4 dataOffset; /* offset to data value */ UMAUint4 dataSize; /* size of data returned in bytes */ } DCIRetval; typedef struct DCIReturn { UMAUint4 size; /* total bytes in DCIReturn */ UMAUint4 count; /* number of returned elements */ DCIStatus sumstatus; /* summary status */ UMATimeSpec startTime; /* Start time of operation */ UMATimeSpec endTime; /* End time of operation */ DCIRetval retval[1]; /* status,input id, and output */ } DCIReturn; typedef UMAUint4 DCIStatus; typedef struct DCIRetval DCIRetval; typedef struct DCIReturn DCIReturn;

Some routines may not return data. In this case there is no returned data area in the DCIReturn structure and the dataOffset and dataSize fields of the DCIRetval structure are unused and their values are set to zero. Clearing these fields prevents applications which inadvertently ignore status values from accessing memory outside of the input buffer range.

The returned data which follows the array of status structures can be used directly as input to other DCI routines. For example, dciListClassId() can return a list of expanded metric class identifiers that can be directly used as input to dciListInstanceId(). This improves application performance by avoiding additional data manipulation for successful requests.

There is no requirement that the DCIReturn structures are returned in the same order as the input metric list nor is there a requirement that any additional return data be in the same order as the DCIReturn structures. It is expected that many implementations will retain the same ordering but there may be an implementation specific performance advantage to writing portions of the return structure out of order.

An application can choose to supply its own buffer for the DCI return structure or have the DCI library allocate a buffer on its behalf. This is done by passing in the address of the return buffer address. If the buffer address is zero then the DCI routine allocates memory and writes the return buffer address. If the buffer address is not zero then the DCI routine writes the return buffer to the given address, limiting the write to the size of the supplied buffer.

In the event that the return buffer supplied is too small to contain the data, the following conditions apply:

The reason for allowing the choice of a DCI allocated buffer or an application allocated buffer is that in most cases applications would want the DCI service to size and allocate the return structure, especially since the DCI service would know in advance the buffer size, but there are cases where the application needs to manage its own memory. An example would be a metrics archival application which wants to have the results of dciGetData() calls be written directly to a memory mapped file. If the If DCI routines did their own memory allocation for the return values then the application would have to copy the results to the proper address in the mapped region. By having the interface write the return structure into an application provided address only one write is performed. Thus allowing this choice provides convenience for the typical application while retaining the DCI interface's flexibility.

Note that is implementation defined whether a DCI call using both wildcards and application allocated buffers performs partial work in the event the buffer is too small. For example, a dciRemoveInstance() call with wildcarded instance identifiers may require a very large output buffer to hold the dciRetval structures. If the buffer is allocated by the consuming application, it may be too small. It is implementation defined in this situation whether the DCI removes no instances, or only as many instances for which there is room in the buffer to indicate success.

The two data capture routines, dciGetData() and dciWaitEvent(), allow the consumer to request separate return status and data buffers. This enables metric consumer applications in a data acquisition loop to discard successful, repetitive status returns while archiving the returned data to a sequential buffer. The DCI service allocates buffer space on behalf of the consumer if either the status or the data buffer address is set to zero. If the address of the data buffer address is zero, the DCI service defaults to writing both status and data to the status buffer address. This behaviour is described in the following tables.

If the address of the data buffer address is not zero, then the consumer application has selected split buffers. In this case, the values of the return status address, the data buffer address and the data buffer size are interpreted as follows:


  Input Value of Zero Input Value of Non-zero
return status address of address of
address server-allocated consumer-allocated
  return buffer return buffer
     
  caller must use  
  dciFreei() to free  
data buffer address of address of
address server-allocated consumer-allocated
  data buffer data buffer
     
  caller must use  
  dciFree() to free  
data buffer size of returned size of consumer-
size data buffer allocated data
    buffer


If the address of the data buffer address is zero, the consumer application has elected to have a single return buffer. In this case, the values of the return status address is interpreted as follows:


  Input Value of Zero Input Value of Non-zero
return status address of address of
address server-allocated consumer-allocated
  return buffer return buffer
     
    (with data buffer
  caller must use in it).
  dciFree() to free  


If a consumer decides to split the status and data buffers then the size field in the DCIReturn structure in the status buffer refers to only the size of the status structure, it does not include the size of the data area. Also, the dataOffset fields in the DCIReturn structure reflect the offset from the beginning of the data buffer. The consumer can examine the returned dataSize argument provided with the dciGetData() and dciWaitEvent() routines to discover the data buffer size.


Why not acquire a nicely bound hard copy?
Click here to return to the publication details or order a copy of this publication.

Contents Next section Index