Contents:
Introduction
The Solaris kernel provides a set of functions and data structures for device drivers and other kernel modules to export module-specific statistics to the outside world. This infrastructure, referred to as
The Solaris
Since many developers are interested in accessing kernel statistics through C programs, this article focuses on using Data Structure Overview
Solaris kernel statistics are maintained in a linked list of structures referred to as the
The chain is initialized at system boot time, but since Solaris is a dynamic operating system, this chain may change over time.
The structure member
Example 1 shows the full
Example 1 -
typedef struct kstat {
/*
* Fields relevant to both kernel and user
*/
hrtime_t ks_crtime; /* creation time */
struct kstat *ks_next; /* kstat chain linkage */
kid_t ks_kid; /* unique kstat ID */
char ks_module[KSTAT_STRLEN]; /* module name */
uchar_t ks_resv; /* reserved */
int ks_instance; /* module's instance */
char ks_name[KSTAT_STRLEN]; /* kstat name */
uchar_t ks_type; /* kstat data type */
char ks_class[KSTAT_STRLEN]; /* kstat class */
uchar_t ks_flags; /* kstat flags */
void *ks_data; /* kstat type-specific data */
uint_t ks_ndata; /* # of data records */
size_t ks_data_size; /* size of kstat data section */
hrtime_t ks_snaptime; /* time of last data snapshot */
/*
* Fields relevant to kernel only
*/
int (*ks_update)(struct kstat *, int);
void *ks_private;
int (*ks_snapshot)(struct kstat *, void *, int);
void *ks_lock;
} kstat_t;
The significant members include:
Getting Started
To use kstats, a program must first call to
Example 2 -
typedef struct kstat_ctl {
kid_t kc_chain_id; /* current kstat chain ID */
kstat_t *kc_chain; /* pointer to kstat chain */
int kc_kd; /* /dev/kstat descriptor */
} kstat_ctl_t;
To avoid unnecessary overhead accessing
Example 3 is a code fragment that shows how you might print out all How to implement this sample function is shown in Example 9.
Example 3 - Print
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_io_t kio;
kc = kstat_open();
for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
if (ksp->ks_type == KSTAT_TYPE_IO) {
kstat_read(kc, ksp, &kio);
my_io_display(kio);
}
}
Data Types
The data section of a
The field KSTAT_TYPE_RAW
The "raw"
Example 4 - Dumping Out a Raw
static void print_vminfo(kstat_t *kp)
{
vminfo_t *vminfop;
vminfop = (vminfo_t *)(kp->ks_data);
printf("Free memory: %dn", vminfop->freemem);
printf("Swap reserved: %dn" , vminfop->swap_resv);
printf("Swap allocated: %dn" , vminfop->swap_alloc);
printf("Swap available: %dn", vminfop->swap_avail);
printf("Swap free: %dn", vminfop->swap_free);
}
KSTAT_TYPE_NAMED
This type of
Example 5 - Named
typedef struct kstat_named {
char name[KSTAT_STRLEN]; /* name of counter */
uchar_t data_type; /* data type */
union {
char c[16]; /* enough for 128-bit ints */
int32_t i32;
uint32_t ui32;
int64_t i64;
uint64_t ui64;
/* These structure members are obsolete */
int32_t l;
uint32_t ul;
int64_t ll;
uint64_t ull;
} value; /* value of counter */
} kstat_named_t;
#define KSTAT_DATA_CHAR 0
#define KSTAT_DATA_INT32 1
#define KSTAT_DATA_UINT32 2
#define KSTAT_DATA_INT64 3
#define KSTAT_DATA_UINT64 4
/* These types are obsolete */
#define KSTAT_DATA_LONG 1
#define KSTAT_DATA_ULONG 2
#define KSTAT_DATA_LONGLONG 3
#define KSTAT_DATA_ULONGLONG 4
#define KSTAT_DATA_FLOAT 5
#define KSTAT_DATA_DOUBLE 6
The program in Example 9 uses a function
Note that if the type is KSTAT_TYPE_TIMER
This
Example 6 - Timer
typedef struct kstat_timer {
char name[KSTAT_STRLEN]; /* event name */
uchar_t resv; /* reserved */
u_longlong_t num_events; /* number of events */
hrtime_t elapsed_time; /* cumulative elapsed time */
hrtime_t min_time; /* shortest event duration */
hrtime_t max_time; /* longest event duration */
hrtime_t start_time; /* previous event start time */
hrtime_t stop_time; /* previous event stop time */
} kstat_timer_t;
KSTAT_TYPE_INTR
This type of
Example 7 - Interrupt
#define KSTAT_INTR_HARD 0
#define KSTAT_INTR_SOFT 1
#define KSTAT_INTR_WATCHDOG 2
#define KSTAT_INTR_SPURIOUS 3
#define KSTAT_INTR_MULTSVC 4
#define KSTAT_NUM_INTRS 5
typedef struct kstat_intr {
uint_t intrs[KSTAT_NUM_INTRS]; /* interrupt counters */
} kstat_intr_t;
KSTAT_TYPE_IO
Example 8 - I/O
typedef struct kstat_io {
/*
* Basic counters.
*/
u_longlong_t nread; /* number of bytes read */
u_longlong_t nwritten; /* number of bytes written */
uint_t reads; /* number of read operations */
uint_t writes; /* number of write operations */
hrtime_t wtime; /* cumulative wait (pre-service) time */
hrtime_t wlentime; /* cumulative wait length*time product*/
hrtime_t wlastupdate; /* last time wait queue changed */
hrtime_t rtime; /* cumulative run (service) time */
hrtime_t rlentime; /* cumulative run length*time product */
hrtime_t rlastupdate; /* last time run queue changed */
uint_t wcnt; /* count of elements in wait state */
uint_t rcnt; /* count of elements in run state */
} kstat_io_t;
Accumulated Time and Queue Length StatisticsTime statistics are kept as a running sum of "active" time. Queue length statistics are kept as a running sum of the product of queue length and elapsed time at that length that is, a Riemann sum for queue length integrated against time. Figure 2 provides a sample graphical representation of queue/time.
At each change of state (either an entry or exit from the queue), the elapsed time since the previous state change is added to the active time (
The product of the elapsed time and the queue length is added to the running sum of the length (field Stated programmatically:
if (queue length != 0) {
time += elapsed time since last state change;
lentime += (elapsed time since last state change * queue length);
}
This method can be generalized to measuring residency in any defined system. Instead of queue lengths, think of "outstanding RPC calls to server X." A large number of I/O subsystems have at least two basic "lists" of transactions they manage:
For these reasons, two cumulative time statistics are defined:
The units of cumulative busy time are accumulated nanoseconds. kstat Names
The
The combination of these three fields is guaranteed to be unique.
For example, imagine a system with four FastEthernet interfaces. The device driver module for Sun's FastEthernet controller is called "hme". The first Ethernet interface would be instance 0, the second instance 1, and so on. The "hme" driver provides two types of
The
In that example, the combination of module name and instance number to make the
How do you determine what kstats the kernel provides? One of the easiest ways, with Solaris 8, is to run Functions
The following functions are available to C programs for accessing
Dealing with Chain Updates
As mentioned in Data Structure Overview, the
Each time a kernel module adds or removes a
If your program has cached some local data from previous calls to the
A practical example is the system command Putting It All TogetherYour C source file must contain:
When your program is linked, the compiler command line must include the argument
The following is a short example program. First, it uses Example 9 - Sample Program to Print kstats of Different Types
/* print_some_kstats.c:
* print out a couple of interesting things
*/
#include <kstat.h>
#include <stdio.h>
#include <inttypes.h>
#define SLEEPTIME 10
void my_named_display(char *, char *, kstat_named_t *);
void my_io_display(char *, char *, kstat_io_t);
main(int argc, char **argv)
{
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_io_t kio;
kstat_named_t *knp;
kc = kstat_open();
/*
* Print out the CPU speed. We make two assumptions here:
* 1) All CPUs are the same speed, so we'll just search for the
* first one;
* 2) At least one CPU is online, so our search will always
* find something. :)
*/
ksp = kstat_lookup(kc, "cpu_info", -1, NULL);
kstat_read(kc, ksp, NULL);
/* lookup the CPU speed data record */
knp = kstat_data_lookup(ksp, "clock_MHz");
printf("CPU speed of system is ");
my_named_display(ksp->ks_name, ksp->ks_class, knp);
printf("n");
/* dump some info about all I/O kstats every
SLEEPTIME seconds */
while(1) {
/* make sure we have current data */
if(kstat_chain_update(kc))
fprintf(stderr, "<<State Changed>>n");
for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
if (ksp->ks_type == KSTAT_TYPE_IO) {
kstat_read(kc, ksp, &kio);
my_io_display(ksp->ks_name, ksp->ks_class, kio);
}
}
sleep(SLEEPTIME);
} /* while(1) */
}
void my_io_display(char *devname, char *class, kstat_io_t k)
{
printf("Name: %s Class: %sn",devname,class);
printf("tnumber of bytes read %lldn", k.nread);
printf("tnumber of bytes written %lldn", k.nwritten);
printf("tnumber of read operations %dn", k.reads);
printf("tnumber of write operations %dnn", k.writes);
}
void
my_named_display(char *devname, char *class, kstat_named_t *knp)
{
switch(knp->data_type) {
case KSTAT_DATA_CHAR:
printf("%.16s",knp->value.c);
break;
case KSTAT_DATA_INT32:
printf("%" PRId32,knp->value.i32);
break;
case KSTAT_DATA_UINT32:
printf("%" PRIu32,knp->value.ui32);
break;
case KSTAT_DATA_INT64:
printf("%" PRId64,knp->value.i64);
break;
case KSTAT_DATA_UINT64:
printf("%" PRIu64,knp->value.ui64);
}
}
Additional Information
Much of the information in this paper derives from various SunSolve InfoDocs, Solaris white papers, and Solaris man pages (section July 2001 | |||||||||||||||||||||||
|
| ||||||||||||