[BACK]Return to dkstats.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vmstat

Annotation of src/usr.bin/vmstat/dkstats.c, Revision 1.2

1.2     ! deraadt     1: /*     $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $      */
1.1       tholo       2:
                      3: /*
1.2     ! deraadt     4:  * Copyright (c) 1996 John M. Vinopal
1.1       tholo       5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *      This product includes software developed for the NetBSD Project
                     18:  *      by John M. Vinopal.
                     19:  * 4. The name of the author may not be used to endorse or promote products
                     20:  *    derived from this software without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     27:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     28:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     29:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     30:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
                     35: #include <sys/dkstat.h>
                     36: #include <sys/time.h>
                     37: #include <sys/disk.h>
                     38:
                     39: #include <err.h>
                     40: #include <fcntl.h>
                     41: #include <kvm.h>
                     42: #include <limits.h>
                     43: #include <nlist.h>
                     44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
                     47: #include <unistd.h>
                     48: #include "dkstats.h"
                     49:
                     50: static struct nlist namelist[] = {
                     51: #define        X_TK_NIN        0
                     52:        { "_tk_nin" },          /* tty characters in */
                     53: #define        X_TK_NOUT       1
                     54:        { "_tk_nout" },         /* tty characters out */
                     55: #define        X_CP_TIME       2
                     56:        { "_cp_time" },         /* system timer ticks */
                     57: #define        X_HZ            3
                     58:        { "_hz" },              /* ticks per second */
                     59: #define        X_STATHZ        4
                     60:        { "_stathz" },
                     61: #define X_DISK_COUNT   5
                     62:        { "_disk_count" },      /* number of disks */
                     63: #define X_DISKLIST     6
                     64:        { "_disklist" },        /* TAILQ of disks */
                     65:        { NULL },
                     66: };
                     67:
                     68: /* Structures to hold the statistics. */
                     69: struct _disk   cur, last;
                     70:
                     71: /* Kernel pointers: nlistf and memf defined in calling program. */
                     72: static kvm_t   *kd = NULL;
                     73: extern char    *nlistf;
                     74: extern char    *memf;
                     75:
                     76: /* Pointer to list of disks. */
                     77: static struct disk     *dk_drivehead = NULL;
                     78:
                     79: /* Backward compatibility references. */
                     80: int            dk_ndrive = 0;
                     81: int            *dk_select;
                     82: char           **dr_name;
                     83:
                     84: #define        KVM_ERROR(_string) {                                            \
                     85:        warnx((_string));                                               \
                     86:        errx(1, kvm_geterr(kd));                                        \
                     87: }
                     88:
                     89: /*
                     90:  * Dereference the namelist pointer `v' and fill in the local copy
                     91:  * 'p' which is of size 's'.
                     92:  */
                     93: #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
                     94:
                     95: /* Missing from <sys/time.h> */
                     96: #define timerset(tvp, uvp) ((uvp)->tv_sec = (tvp)->tv_sec);            \
                     97:                           ((uvp)->tv_usec = (tvp)->tv_usec)
                     98:
                     99: void dkswap __P((void));
                    100: void dkreadstats __P((void));
                    101: int dkinit __P((int));
1.2     ! deraadt   102: static void deref_kptr __P((void *, void *, size_t));
1.1       tholo     103:
                    104: /*
                    105:  * Take the delta between the present values and the last recorded
                    106:  * values, storing the present values in the 'last' structure, and
                    107:  * the delta values in the 'cur' structure.
                    108:  */
                    109: void
                    110: dkswap()
                    111: {
                    112: #define SWAP(fld)              tmp = cur.fld;                          \
                    113:                                cur.fld -= last.fld;                    \
                    114:                                last.fld = tmp
                    115:        u_int64_t tmp;
                    116:        int     i;
                    117:
                    118:        for (i = 0; i < dk_ndrive; i++) {
                    119:                struct timeval  tmp_timer;
                    120:
                    121:                if (!cur.dk_select[i])
                    122:                        continue;
                    123:
                    124:                /* Delta Values. */
                    125:                SWAP(dk_xfer[i]);
                    126:                SWAP(dk_seek[i]);
                    127:                SWAP(dk_bytes[i]);
                    128:
                    129:                /* Delta Time. */
                    130:                timerclear(&tmp_timer);
                    131:                timerset(&(cur.dk_time[i]), &tmp_timer);
                    132:                timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i]));
                    133:                timerclear(&(last.dk_time[i]));
                    134:                timerset(&tmp_timer, &(last.dk_time[i]));
                    135:        }
                    136:        for (i = 0; i < CPUSTATES; i++) {
                    137:                SWAP(cp_time[i]);
                    138:        }
                    139:        SWAP(tk_nin);
                    140:        SWAP(tk_nout);
                    141:
                    142: #undef SWAP
                    143: }
                    144:
                    145: /*
                    146:  * Read the disk statistics for each disk in the disk list.
                    147:  * Also collect statistics for tty i/o and cpu ticks.
                    148:  */
                    149: void
                    150: dkreadstats()
                    151: {
                    152:        struct disk     cur_disk, *p;
                    153:        int             i;
                    154:
                    155:        p = dk_drivehead;
                    156:
                    157:        for (i = 0; i < dk_ndrive; i++) {
                    158:                deref_kptr(p, &cur_disk, sizeof(cur_disk));
                    159:                cur.dk_xfer[i] = cur_disk.dk_xfer;
                    160:                cur.dk_seek[i] = cur_disk.dk_seek;
                    161:                cur.dk_bytes[i] = cur_disk.dk_bytes;
                    162:                timerset(&(cur_disk.dk_time), &(cur.dk_time[i]));
                    163:                p = cur_disk.dk_link.tqe_next;
                    164:        }
                    165:        deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time));
                    166:        deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
                    167:        deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
                    168: }
                    169:
                    170: /*
                    171:  * Perform all of the initialization and memory allocation needed to
                    172:  * track disk statistics.
                    173:  */
                    174: int
                    175: dkinit(select)
                    176: int    select;
                    177: {
                    178:        struct disklist_head disk_head;
                    179:        struct disk     cur_disk, *p;
                    180:         char           errbuf[_POSIX2_LINE_MAX];
                    181:        static int      once = 0;
                    182:        extern int      hz;
                    183:        int             i;
                    184:
                    185:        if (once)
                    186:                return(1);
                    187:
                    188:        /* Open the kernel. */
                    189:         if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
                    190:                errx(1, "kvm_openfiles: %s", errbuf);
                    191:
                    192:        /* Obtain the namelist symbols from the kernel. */
                    193:        if (kvm_nlist(kd, namelist))
                    194:                KVM_ERROR("kvm_nlist failed to read symbols.");
                    195:
                    196:        /* Get the number of attached drives. */
                    197:        deref_nl(X_DISK_COUNT, &dk_ndrive, sizeof(dk_ndrive));
                    198:
                    199:        if (dk_ndrive < 0)
                    200:                errx(1, "invalid _disk_count %d.", dk_ndrive);
                    201:        else if (dk_ndrive == 0) {
                    202:                warnx("No drives attached.");
                    203:        }
                    204:        else {
                    205:                /* Get a pointer to the first disk. */
                    206:                deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
                    207:                dk_drivehead = disk_head.tqh_first;
                    208:        }
                    209:
                    210:        /* Get ticks per second. */
                    211:        deref_nl(X_STATHZ, &hz, sizeof(hz));
                    212:        if (!hz)
                    213:                deref_nl(X_HZ, &hz, sizeof(hz));
                    214:
                    215:        /* allocate space for the statistics */
                    216:        cur.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
                    217:        cur.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
                    218:        cur.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
                    219:        cur.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
                    220:        last.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
                    221:        last.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
                    222:        last.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
                    223:        last.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
                    224:        cur.dk_select = calloc(dk_ndrive, sizeof(int));
                    225:        cur.dk_name = calloc(dk_ndrive, sizeof(char *));
                    226:
                    227:        if (!cur.dk_time || !cur.dk_xfer || !cur.dk_seek || !cur.dk_bytes
                    228:            || !last.dk_time || !last.dk_xfer || !last.dk_seek || !last.dk_bytes
                    229:            || !cur.dk_select || !cur.dk_name)
                    230:                errx(1, "Memory allocation failure.");
                    231:
                    232:        /* Set up the compatibility interfaces. */
                    233:        dk_select = cur.dk_select;
                    234:        dr_name = cur.dk_name;
                    235:
                    236:        /* Read the disk names and set intial selection. */
                    237:        p = dk_drivehead;
                    238:        for (i = 0; i < dk_ndrive; i++) {
                    239:                char    buf[10];
                    240:                deref_kptr(p, &cur_disk, sizeof(cur_disk));
                    241:                deref_kptr(cur_disk.dk_name, buf, sizeof(buf));
                    242:                cur.dk_name[i] = strdup(buf);
                    243:                cur.dk_select[i] = select;
                    244:
                    245:                p = cur_disk.dk_link.tqe_next;
                    246:        }
                    247:
                    248:        /* Never do this initalization again. */
                    249:        once = 1;
                    250:        return(1);
                    251: }
                    252:
                    253: /*
                    254:  * Dereference the kernel pointer `kptr' and fill in the local copy
                    255:  * pointed to by `ptr'.  The storage space must be pre-allocated,
                    256:  * and the size of the copy passed in `len'.
                    257:  */
                    258: static void
                    259: deref_kptr(kptr, ptr, len)
                    260:        void *kptr, *ptr;
                    261:        size_t len;
                    262: {
                    263:        char buf[128];
                    264:
                    265:        if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
                    266:                bzero(buf, sizeof(buf));
                    267:                snprintf(buf, (sizeof(buf) - 1),
1.2     ! deraadt   268:                     "can't dereference kptr 0x%lx", (u_long)kptr);
1.1       tholo     269:                KVM_ERROR(buf);
                    270:        }
                    271: }