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.
Most DCI structures have the same 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.
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
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.
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:
The structures are defined as follows:
-
-
typedef struct DCIClassId {
UMAUint4 size;
UMAVarLenData data;
} DCIClassId;
The usage of the structure elements is as follows:
-
-
typedef UMAUint4 DCIDatumId;
The usage of the structure elements is as follows:
The usage of the structure elements is as follows:
-
-
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:
The Data Pool is organised as a class/subclass hierarchy. In
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.
-
-
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
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:
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 *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);
}
Thus, to walk the integers in a DCIClassId, the following code fragment
could be used:
Note that the size of each array element is always four bytes.
The DCI does not reserve any instance values to represent wildcards
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.
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
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
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.
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
-
-
typedef struct DCIAccess {
UMAUint4 size;
UMAVarLenData access;
} DCIAccess;
The usage of the structure elements is as follows:
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.
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:
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
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
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
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.
The usage of the structure elements is as follows:
The relationship between the various fields in this data structure is
illustrated in the DCIClassAttr diagram in
The DCILabel structure is:
The usage of the structure elements is as follows:
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:
This reservation allows implementers to record meta-information in
labels associated with datumIds, Class Attributes and Instance Attributes.
The DCIInstLevel structure is shown in
The usage of the structure elements is as follows:
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
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 |
Note that there is a special kind of instance type called
UMA_SINGLEINST. This is the instance level type used by a provider
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.
-
-
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:
-
-
typedef struct DCIEventAttr {
UMAUint4 size;
DCIDatumId datumId;
UMAVarLenDescr label;
UMAVarArrayDescr eventDataAttr;
UMAVarLenData data;
} DCIEventAttr;
The usage of the structure elements is as follows:
-
-
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:
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:
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.
-
-
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:
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
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:
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:
Note that the structure of events lacking an event header is implementation defined.
The usage of the structure elements is as follows:
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.
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. |
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.
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.
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 |
Time | |
---|---|
UMA_SECS | seconds |
UMA_MILLISECS | milliseconds |
UMA_MICROSECS | microseconds |
UMA_NANOSECS | nanoseconds |
UMA_PICOSECS | picoseconds |
UMA_TICKS | machine clock ticks |
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 |
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 |
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 |
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 |
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 |
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.
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 |
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() |
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
The usage of the structure elements is as follows:
Not every method type can support every operation. Although described in
detail below,
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 |
The following sections describe the use of provider operations, dciPostData() and methods in detail.
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.
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.
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
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.
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.
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.
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.
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,
When this method is used, each dciAddInstance() call, for which this
If the DCI_OP_GETDATA operation on a metric is supported by the
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
The usage of the structure elements is as follows:
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.
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:
The usage of the structure elements is as follows:
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
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:
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
If the operation is DCI_OP_LISTINSTANCES, only metric
If the operation is DCI_OP_GETINSTATTR, only metric identifiers
If the operation is DCI_OP_CONFIGURE, data is supplied in the
If the operation is DCI_OP_SETDATA or DCI_OP_RESERVEDATA, data
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.
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
The DCIReturn, DCIRetval, and DCIStatus structures and type definitions
are defined as follows:
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()
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.
Contents | Next section | Index |