Files
retrobsd/src/cmd/vmstat.c
2014-04-09 14:27:18 +01:00

445 lines
11 KiB
C

/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <nlist.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/vm.h>
#include <sys/dk.h>
#include <sys/buf.h>
#include <sys/dir.h>
#include <sys/inode.h>
#include <sys/namei.h>
#include <machine/machparam.h>
struct nlist nl[] = {
#define X_CPTIME 0
{ "_cp_time" },
#define X_RATE 1
{ "_rate" },
#define X_TOTAL 2
{ "_total" },
#define X_FORKSTAT 3
{ "_forkstat" },
#define X_SUM 4
{ "_sum" },
#define X_BOOTTIME 5
{ "_boottime" },
#define X_DKXFER 6
{ "_dk_xfer" },
#define X_HZ 7
{ "_hz" },
#define X_NCHSTATS 8
{ "_nchstats" },
#define X_DK_NDRIVE 9
{ "_dk_ndrive" },
#define X_DK_NAME 10
{ "_dk_name" },
#define X_DK_UNIT 11
{ "_dk_unit" },
#define X_FREEMEM 12
{ "_freemem" },
{ "" },
};
char **dk_name;
int *dk_unit;
size_t pfree;
int pflag;
char **dr_name;
int *dr_select;
int dk_ndrive;
int ndrives = 0;
char *defdrives[] = { "sd0", 0 };
double stat1();
int hz;
struct {
int busy;
long time[CPUSTATES];
long *xfer;
struct vmrate Rate;
struct vmtotal Total;
struct vmsum Sum;
struct forkstat Forkstat;
unsigned rectime;
unsigned pgintime;
} s, s1, z;
#define rate s.Rate
#define total s.Total
#define sum s.Sum
#define forkstat s.Forkstat
struct vmsum osum;
double etime;
int mf;
time_t now, boottime;
int lines = 1;
void printhdr(sig)
int sig;
{
register int i, j;
if (pflag)
printf("-procs- -----memory----- -swap- ");
else
printf("-procs- ---memory-- ");
printf("-----disks----- ");
if (pflag) {
printf("-----faults----- ------cpu------\n");
printf(" r b w avm tx fre i o ");
} else {
printf("---faults--- ----cpu----\n");
printf(" r b w avm fre ");
}
for (i = 0; i < dk_ndrive; i++)
if (dr_select[i])
printf("%c%c%c ",
dr_name[i][0], dr_name[i][1], dr_name[i][2]);
printf(" in sy");
if (pflag)
printf(" tr");
printf(" cs us");
if (pflag)
printf(" ni");
printf(" sy id\n");
lines = 19;
}
main(argc, argv)
int argc;
char **argv;
{
extern char *ctime();
register i;
int iter, iflag = 0;
long nintv, t;
char *arg, **cp, buf[BUFSIZ];
knlist(nl);
if(nl[0].n_value == 0) {
fprintf(stderr, "no /vmunix namelist\n");
exit(1);
}
mf = open("/dev/kmem", 0);
if(mf < 0) {
fprintf(stderr, "cannot open /dev/kmem\n");
exit(1);
}
iter = 0;
argc--, argv++;
while (argc>0 && argv[0][0]=='-') {
char *cp = *argv++;
argc--;
while (*++cp) switch (*cp) {
case 't':
dotimes();
exit(0);
case 'z':
close(mf);
mf = open("/dev/kmem", 2);
lseek(mf, (long)nl[X_SUM].n_value, L_SET);
write(mf, &z.Sum, sizeof z.Sum);
exit(0);
case 'f':
doforkst();
exit(0);
case 's':
dosum();
exit(0);
case 'i':
iflag++;
break;
case 'p':
pflag++;
break;
default:
fprintf(stderr,
"usage: vmstat [ -fsiptz ] [ interval ] [ count]\n");
exit(1);
}
}
lseek(mf, (long)nl[X_BOOTTIME].n_value, L_SET);
read(mf, &boottime, sizeof boottime);
lseek(mf, (long)nl[X_HZ].n_value, L_SET);
read(mf, &hz, sizeof hz);
if (nl[X_DK_NDRIVE].n_value == 0) {
fprintf(stderr, "dk_ndrive undefined in system\n");
exit(1);
}
lseek(mf, (long)nl[X_DK_NDRIVE].n_value, L_SET);
read(mf, &dk_ndrive, sizeof (dk_ndrive));
if (dk_ndrive <= 0) {
fprintf(stderr, "dk_ndrive %d\n", dk_ndrive);
exit(1);
}
dr_select = (int *)calloc(dk_ndrive, sizeof (int));
dr_name = (char **)calloc(dk_ndrive, sizeof (char *));
dk_name = (char **)calloc(dk_ndrive, sizeof (char *));
dk_unit = (int *)calloc(dk_ndrive, sizeof (int));
#define allocate(e, t) \
s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
allocate(xfer, long);
for (arg = buf, i = 0; i < dk_ndrive; i++) {
dr_name[i] = arg;
sprintf(dr_name[i], "dk%d", i);
arg += strlen(dr_name[i]) + 1;
}
read_names();
time(&now);
nintv = now - boottime;
if (nintv <= 0 || nintv > 60L*60L*24L*365L*10L) {
fprintf(stderr,
"Time makes no sense... namelist must be wrong.\n");
exit(1);
}
if (iflag) {
dointr(nintv);
exit(0);
}
/*
* Choose drives to be displayed. Priority
* goes to (in order) drives supplied as arguments,
* default drives. If everything isn't filled
* in and there are drives not taken care of,
* display the first few that fit.
*/
ndrives = 0;
while (argc > 0 && !isdigit(argv[0][0])) {
for (i = 0; i < dk_ndrive; i++) {
if (strcmp(dr_name[i], argv[0]))
continue;
dr_select[i] = 1;
ndrives++;
}
argc--, argv++;
}
for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
if (dr_select[i])
continue;
for (cp = defdrives; *cp; cp++)
if (strcmp(dr_name[i], *cp) == 0) {
dr_select[i] = 1;
ndrives++;
break;
}
}
for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
if (dr_select[i])
continue;
dr_select[i] = 1;
ndrives++;
}
if (argc > 1)
iter = atoi(argv[1]);
signal(SIGCONT, printhdr);
loop:
if (--lines == 0)
printhdr();
lseek(mf, (long)nl[X_CPTIME].n_value, L_SET);
read(mf, s.time, sizeof s.time);
lseek(mf, (long)nl[X_DKXFER].n_value, L_SET);
read(mf, s.xfer, dk_ndrive * sizeof (long));
if (nintv != 1) {
lseek(mf, (long)nl[X_SUM].n_value, L_SET);
read(mf, &sum, sizeof(sum));
rate.v_swtch = sum.v_swtch;
rate.v_trap = sum.v_trap;
rate.v_syscall = sum.v_syscall;
rate.v_intr = sum.v_intr;
rate.v_swpin = sum.v_swpin;
rate.v_swpout = sum.v_swpout;
} else {
lseek(mf, (long)nl[X_RATE].n_value, L_SET);
read(mf, &rate, sizeof rate);
lseek(mf, (long)nl[X_SUM].n_value, L_SET);
read(mf, &sum, sizeof sum);
}
lseek(mf, (long)nl[X_FREEMEM].n_value, L_SET);
read(mf, &pfree, sizeof(pfree));
lseek(mf, (long)nl[X_TOTAL].n_value, L_SET);
read(mf, &total, sizeof total);
osum = sum;
lseek(mf, (long)nl[X_SUM].n_value, L_SET);
read(mf, &sum, sizeof sum);
etime = 0;
for (i=0; i < dk_ndrive; i++) {
t = s.xfer[i];
s.xfer[i] -= s1.xfer[i];
s1.xfer[i] = t;
}
for (i=0; i < CPUSTATES; i++) {
t = s.time[i];
s.time[i] -= s1.time[i];
s1.time[i] = t;
etime += s.time[i];
}
if(etime == 0.)
etime = 1.;
printf("%2d%2d%2d", total.t_rq, total.t_dw, total.t_sw);
/*
* We don't use total.t_free because it slops around too much
* within this kernel
*/
printf("%7d", total.t_avm);
if (pflag)
printf("%4d",
total.t_avm ? (total.t_avmtxt * 100) / total.t_avm : 0);
printf("%6d", pfree);
if (pflag) {
printf("%4d%3d ", rate.v_swpin / nintv, rate.v_swpout / nintv);
}
etime /= (float)hz;
for (i = 0; i < dk_ndrive; i++) {
if (dr_select[i])
stats(i);
}
printf("%5d%4d", rate.v_intr/nintv, rate.v_syscall/nintv);
if (pflag)
printf("%4d", rate.v_trap / nintv);
printf("%4d", rate.v_swtch / nintv);
for(i=0; i<CPUSTATES; i++) {
float f = stat1(i);
if (! pflag && i == 0) { /* US+NI */
i++;
f += stat1(i);
}
printf(" %3.0f", f);
}
printf("\n");
fflush(stdout);
nintv = 1;
if (--iter &&argc > 0) {
sleep(atoi(argv[0]));
goto loop;
}
}
dotimes()
{
printf("page in/out/reclamation is not applicable to 2.11BSD\n");
}
dosum()
{
struct nchstats nchstats;
long nchtotal;
lseek(mf, (long)nl[X_SUM].n_value, L_SET);
read(mf, &sum, sizeof sum);
printf("%9d swap ins\n", sum.v_swpin);
printf("%9d swap outs\n", sum.v_swpout);
printf("%9d kbytes swapped in\n", sum.v_kbin);
printf("%9d kbytes swapped out\n", sum.v_kbout);
printf("%9d cpu context switches\n", sum.v_swtch);
printf("%9d device interrupts\n", sum.v_intr);
printf("%9d software interrupts\n", sum.v_soft);
printf("%9d traps\n", sum.v_trap);
printf("%9d system calls\n", sum.v_syscall);
#define nz(x) ((x) ? (x) : 1)
lseek(mf, (long)nl[X_NCHSTATS].n_value, 0);
read(mf, &nchstats, sizeof nchstats);
nchtotal = nchstats.ncs_goodhits + nchstats.ncs_badhits +
nchstats.ncs_falsehits + nchstats.ncs_miss + nchstats.ncs_long;
printf("%9d total name lookups", nchtotal);
printf(" (cache hits %d%% system %d%% per-process)\n",
nchstats.ncs_goodhits * 100 / nz(nchtotal),
nchstats.ncs_pass2 * 100 / nz(nchtotal));
printf("%9s badhits %d, falsehits %d, toolong %d\n", "",
nchstats.ncs_badhits, nchstats.ncs_falsehits, nchstats.ncs_long);
}
doforkst()
{
lseek(mf, (long)nl[X_FORKSTAT].n_value, L_SET);
read(mf, &forkstat, sizeof forkstat);
if (forkstat.cntfork != 0)
printf("%d forks, %d kbytes, average=%.2f\n",
forkstat.cntfork, forkstat.sizfork,
(float) forkstat.sizfork / forkstat.cntfork);
if (forkstat.cntvfork != 0)
printf("%d vforks, %d kbytes, average=%.2f\n",
forkstat.cntvfork, forkstat.sizvfork,
(float) forkstat.sizvfork / forkstat.cntvfork);
}
stats(dn)
{
if (dn >= dk_ndrive) {
printf(" 0");
return;
}
printf("%4.0f", s.xfer[dn]/etime);
}
double
stat1(row)
{
double t;
register i;
t = 0;
for(i=0; i<CPUSTATES; i++)
t += s.time[i];
if(t == 0.)
t = 1.;
return(s.time[row]*100./t);
}
dointr(nintv)
long nintv;
{
printf("Device interrupt statistics are not applicable to 2.11BSD\n");
}
#define steal(where, var) \
lseek(mf, where, L_SET); read(mf, &var, sizeof var);
/*
* Read the drive names out of kmem.
*/
read_names()
{
char two_char[2];
register int i;
lseek(mf, (long)nl[X_DK_NAME].n_value, L_SET);
read(mf, dk_name, dk_ndrive * sizeof (char *));
lseek(mf, (long)nl[X_DK_UNIT].n_value, L_SET);
read(mf, dk_unit, dk_ndrive * sizeof (int));
for(i = 0; dk_name[i]; i++) {
lseek(mf, (long)dk_name[i], L_SET);
read(mf, two_char, sizeof two_char);
sprintf(dr_name[i], "%c%c%d", two_char[0], two_char[1],
dk_unit[i]);
}
}