269 lines
6.4 KiB
C
269 lines
6.4 KiB
C
static char rcsid[] = "$Header: /proj/irix6.5.7m/isms/eoe/cmd/dkstat/RCS/spindle.c,v 1.12 1997/12/12 03:34:24 markgw Exp $";
|
|
/*
|
|
* --- Disk spindle statistics --
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <pcp/pmapi.h>
|
|
|
|
#include "spindle.h"
|
|
|
|
/*
|
|
* spindle_stats() alternates returning buffer 'a' and then 'b'
|
|
* This makes it easy and efficient for the caller to compute deltas.
|
|
*/
|
|
static int ndevs = 0;
|
|
static spindle *stats_a = NULL;
|
|
static spindle *stats_b = NULL;
|
|
static int which_stats = 0; /* 0 means stats_a, 1 means stats_b */
|
|
static int initialized=0;
|
|
|
|
static int ncontrollers = 0;
|
|
static controller *controllers = NULL;
|
|
|
|
/* metric names with ordinal pmid */
|
|
static char *metrics[] = {
|
|
#define PMID_READ 0
|
|
"irix.disk.dev.read",
|
|
#define PMID_WRITE 1
|
|
"irix.disk.dev.write",
|
|
#define PMID_BREAD 2
|
|
"irix.disk.dev.blkread",
|
|
#define PMID_BWRITE 3
|
|
"irix.disk.dev.blkwrite",
|
|
#define PMID_ACTIVE 4
|
|
"irix.disk.dev.active",
|
|
#define PMID_RESPONSE 5
|
|
"irix.disk.dev.response",
|
|
};
|
|
|
|
static char *ctl_metric[] = {
|
|
"irix.disk.ctl.total"
|
|
};
|
|
|
|
#define NMETRICS (sizeof(metrics)/sizeof(metrics[0]))
|
|
|
|
static pmID pmid_list[NMETRICS];
|
|
static pmID pmid_ctl_list[1];
|
|
static pmInDom spindle_indom;
|
|
static pmInDom controller_indom;
|
|
|
|
int
|
|
spindle_stats_init(spindle **spindle_list)
|
|
{
|
|
int err;
|
|
pmDesc desc;
|
|
int i, j;
|
|
int *inst_list;
|
|
char *p;
|
|
char **name_list;
|
|
|
|
if (initialized)
|
|
fprintf(stderr, "spindle_stats_init: should only be called once");
|
|
initialized++;
|
|
|
|
ndevs = 0;
|
|
|
|
/* scan the disk instance domain and allocate each spindle */
|
|
if ((err = pmLookupName(NMETRICS, metrics, pmid_list)) < 0) {
|
|
fprintf(stderr, "pmLookupName failed: ");
|
|
return err;
|
|
}
|
|
|
|
if ((err = pmLookupName(1, ctl_metric, pmid_ctl_list)) < 0) {
|
|
fprintf(stderr, "pmLookupName failed: ");
|
|
return err;
|
|
}
|
|
|
|
if ((err = pmLookupDesc(pmid_list[0], &desc)) < 0) {
|
|
fprintf(stderr, "pmLookupDesc failed: ");
|
|
return err;
|
|
}
|
|
spindle_indom = desc.indom;
|
|
|
|
if ((err = pmGetInDom(spindle_indom, &inst_list, &name_list)) < 0) {
|
|
fprintf(stderr, "pmGetInDom failed to lookup disk spindle instance domain: ");
|
|
return err;
|
|
}
|
|
|
|
ndevs = err;
|
|
if (ndevs == 0) {
|
|
fprintf(stderr, "diskless system?");
|
|
return 0;
|
|
}
|
|
|
|
if ((stats_a = (spindle *)malloc(ndevs * sizeof(spindle))) == NULL) {
|
|
fprintf(stderr, "out of memory allocating spindles");
|
|
return -errno;
|
|
}
|
|
if ((stats_b = (spindle *)malloc(ndevs * sizeof(spindle))) == NULL) {
|
|
fprintf(stderr, "out of memory allocating spindles");
|
|
return -errno;
|
|
}
|
|
memset(stats_a, 0, ndevs * sizeof(spindle));
|
|
|
|
for (i=0; i < ndevs; i++) {
|
|
stats_a[i].id = inst_list[i];
|
|
stats_a[i].dname = strdup(name_list[i]);
|
|
stats_a[i].wname = strlen(stats_a[i].dname);
|
|
p = stats_a[i].dname + 3;
|
|
while (*p != NULL && isdigit(*p))
|
|
p++;
|
|
if (*p == 'd')
|
|
p++; /* dks[0-9]*d */
|
|
stats_a[i].unit = p;
|
|
}
|
|
|
|
free(inst_list); inst_list = NULL;
|
|
free(name_list); name_list = NULL;
|
|
memcpy(stats_b, stats_a, ndevs * sizeof(spindle));
|
|
|
|
if ((err = pmLookupDesc(pmid_ctl_list[0], &desc)) < 0) {
|
|
fprintf(stderr, "pmLookupDesc failed to lookup descriptor for controllers");
|
|
return err;
|
|
}
|
|
controller_indom = desc.indom;
|
|
|
|
if ((err = pmGetInDom(controller_indom, &inst_list, &name_list)) < 0) {
|
|
fprintf(stderr, "pmGetInDom failed to lookup disk controller instance domain");
|
|
return err;
|
|
}
|
|
ncontrollers = err;
|
|
|
|
if ((controllers = (controller *)malloc(ncontrollers * sizeof(controller))) == NULL)
|
|
fprintf(stderr, "out of memory allocating disk controllers");
|
|
memset(controllers, 0, ncontrollers * sizeof(controller));
|
|
|
|
for (i=0; i < ncontrollers; i++) {
|
|
controller *c = &controllers[i];
|
|
c->id = inst_list[i];
|
|
c->dname = strdup(name_list[i]);
|
|
c->wname = strlen(c->dname);
|
|
/* printf("controller<%s>", c->dname); */
|
|
/* find all the drives on this controller */
|
|
for (c->ndrives=0, c->drives=NULL, j=0; j < ndevs; j++) {
|
|
if (strncmp(c->dname, stats_a[j].dname, c->wname) == 0 && stats_a[j].dname[c->wname] == 'd') {
|
|
c->ndrives++;
|
|
if ((c->drives = (int *)realloc(c->drives, c->ndrives * sizeof(int))) == NULL)
|
|
return -errno;
|
|
c->drives[c->ndrives-1] = j;
|
|
/* printf(" disk<%s>", stats_a[j].dname); */
|
|
}
|
|
}
|
|
/* printf("\n"); */
|
|
}
|
|
|
|
/* success */
|
|
*spindle_list = stats_a;
|
|
return ndevs;
|
|
}
|
|
|
|
static void
|
|
extract_values(pmResult *r, spindle *stats)
|
|
{
|
|
int i, j, k;
|
|
pmValueSet *vs;
|
|
pmValue *v;
|
|
|
|
for (i=0; i < r->numpmid; i++) {
|
|
vs = r->vset[i];
|
|
if (vs->numval < 0) {
|
|
fprintf(stderr, "fetch failed for metric %d\n", i);
|
|
continue;
|
|
}
|
|
for (j=0; j < vs->numval; j++) {
|
|
v = &vs->vlist[j];
|
|
for (k=0; k < ndevs; k++) {
|
|
if (v->inst == stats[k].id) {
|
|
switch (i) { /* ordinal pmid in pmid_list */
|
|
case PMID_READ:
|
|
stats[k].reads = v->value.lval;
|
|
break;
|
|
case PMID_WRITE:
|
|
stats[k].writes = v->value.lval;
|
|
break;
|
|
case PMID_BREAD:
|
|
stats[k].breads = v->value.lval;
|
|
break;
|
|
case PMID_BWRITE:
|
|
stats[k].bwrites = v->value.lval;
|
|
break;
|
|
case PMID_ACTIVE:
|
|
stats[k].active = v->value.lval;
|
|
break;
|
|
case PMID_RESPONSE:
|
|
stats[k].response = v->value.lval;
|
|
break;
|
|
default:
|
|
assert(0); /* coding botch */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (k == ndevs) {
|
|
fprintf(stderr, "Error: instance %d \"%s\" not found in fetch result\n",
|
|
stats[k].id, stats[k].dname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
spindle_stats(spindle **spindle_list, struct timeval *fetchtime)
|
|
{
|
|
int err;
|
|
spindle *ret;
|
|
pmResult *res;
|
|
|
|
if (!initialized) {
|
|
fprintf(stderr, "spindle_stats: spindle_stats_init() has not been called");
|
|
exit(1);
|
|
}
|
|
|
|
ret = which_stats ? stats_a : stats_b;
|
|
which_stats = which_stats ? 0 : 1;
|
|
|
|
/* do a fetch, extract results */
|
|
if ((err = pmFetch(NMETRICS, pmid_list, &res)) < 0)
|
|
return err;
|
|
|
|
extract_values(res, ret);
|
|
|
|
/* success */
|
|
*fetchtime = res->timestamp;
|
|
*spindle_list = ret;
|
|
pmFreeResult(res);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
spindle_stats_profile(int *inclusion_map)
|
|
{
|
|
int err;
|
|
int i, nlist=0, *list;
|
|
|
|
if ((err = pmDelProfile(spindle_indom, 0, NULL)) < 0)
|
|
return err;
|
|
if ((list = (int *)malloc(ndevs * sizeof(int))) == NULL)
|
|
return -errno;
|
|
|
|
for (i=0; i < ndevs; i++) {
|
|
if (inclusion_map[i])
|
|
list[nlist++] = stats_a[i].id;
|
|
}
|
|
|
|
err = pmAddProfile(spindle_indom, nlist, list);
|
|
free(list);
|
|
|
|
return err;
|
|
}
|
|
|
|
controller *
|
|
controller_info(int *n)
|
|
{
|
|
*n = ncontrollers;
|
|
return controllers;
|
|
}
|