pdp11v/usr/src/cmd/sa/sadc.c
/* sadc.c 1.7 of 6/28/82 */
/*
sadc.c - writes system activity binary data from /dev/kmem to a
file or stdout.
Usage: sadc [t n] [file]
if t and n are not specified, it writes
a dummy record to data file. This usage is
particularly used at system booting.
If t and n are specified, it writes system data n times to
file every t seconds.
In both cases, if file is not specified, it writes
data to stdout.
*/
#include <sys/types.h>
#include <sys/param.h>
#if pdp11 || vax
#include <sys/sysmacros.h>
#endif
#ifdef u3b
#include <sys/macro.h>
#include <sys/seg.h>
#endif
#include <sys/var.h>
#include <sys/iobuf.h>
#include <sys/stat.h>
#include <sys/elog.h>
#include <sys/inode.h>
#include <sys/text.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/sysinfo.h>
#include "sa.h"
#ifdef u3b
#include <sys/un52.h>
#include <sys/dma.h>
#include <sys/vtoc.h>
#include <sys/dfc.h>
#define ctob(x) ptob(x)
int dskcnt, un52cnt;
char *taploc,*dskloc;
#endif
#ifdef u370
#include <sys/times.h>
#include <sst.h>
time_t times();
#endif
struct stat ubuf,syb;
struct var tbl;
struct syserr err;
#if pdp11 || vax
struct iotime ia[NCTRA][NDRA];
struct iotime ib[NCTRB][NDRB];
struct iotime ic[NCTRC][NDRC];
struct iotime id[NCTRC][NDRD];
int rlcnt;
int gdcnt;
#endif
struct sa d;
char *flnm = "/tmp/sa.adrfl";
char *loc;
static int fa = 0;
unsigned tblloc;
char *malloc();
#ifndef u370
static int tblmap[SINFO];
#endif
#ifdef u370
static int tblmap[10]; /* A kludge for the 370 -not really used */
#endif
static int recsz,tmpsz;
long time();
int i,j,k;
long lseek();
int f;
static char Sccsid[]="@(#)sadc.c 1.7";
main(argc, argv)
char **argv;
int argc;
{
#ifdef u370
long tmstmp;
struct pxs *pxs;
struct stv *stv;
int sst;
int n;
DEC dp;
struct tms buff;
#endif
int ct;
unsigned ti;
int fp;
long min;
long rem;
struct stat buf;
char *fname;
ct = argc >= 3? atoi(argv[2]): 0;
min = time((long *) 0);
ti = argc >= 3? atoi(argv[1]): 0;
/* check if the address file is there and not older
than /unix, if so, read the offsets in.
Otherwise, search /unix name list to get the offsets
and create an address file for later usage.
*/
stat ("/unix",&syb);
if ((stat(flnm,&ubuf) == -1) ||
(ubuf.st_mtime < syb.st_mtime))
goto creafl;
fa = open(flnm,2);
if (read(fa,setup,sizeof setup) == -1){
creafl:
fa = creat(flnm,00644);
close(fa);
fa = open(flnm,2);
/* search name list to get offsets */
nlist("/unix",setup);
#ifdef vax
for (i=0;i<SERR +1;i++)
setup[i].n_value &= ~(0x80000000);
#endif
#ifdef u370
/* open /dev/mem - get system table addresses */
if((f = open("/dev/mem", 0)) == -1)
exit(2);
for (i = INO; i < V; i++){
lseek(f, setup[i].n_value, 0);
read(f, &setup[i].n_value, 4);
}
/* close /dev/mem */
close(f);
#endif
/* write offsets to address file */
write(fa,setup,sizeof setup);
close (fa);
}
#ifndef u370
/* open /dev/kmem */
if((f = open("/dev/kmem", 0)) == -1)
perrexit();
#endif
#ifdef u370
/* open /dev/mem */
if((f = open("/dev/mem", 0)) == -1)
exit(2);
/* open tss system statistics table */
if((sst = open("/dev/sst",0)) == -1)
exit(2);
#endif
#if pdp11 || vax
/* get number of disk drives on rl and general disk drivers. */
if (setup[RLCNT].n_value != 0){
lseek(f,(long)setup[RLCNT].n_value, 0);
if (read(f,&rlcnt,sizeof rlcnt) == -1)
perrexit();
}
if (setup[GDCNT].n_value != 0){
lseek(f,(long)setup[GDCNT].n_value, 0);
if (read(f,&gdcnt,sizeof gdcnt) == -1)
perrexit();
}
#endif
#ifdef u3b
/* get numbers of tape controller and disk drives for 3B */
if (setup[UN52CNT].n_value !=0){
lseek(f,(long)setup[UN52CNT].n_value, 0);
if (read(f,&un52cnt,sizeof un52cnt) == -1)
perrexit();
taploc = malloc(sizeof (struct un52)*un52cnt*4);
if (taploc == NULL)
perrexit();
}
if (setup[DSKCNT].n_value !=0){
lseek(f,(long)setup[DSKCNT].n_value, 0);
if (read(f,&dskcnt,sizeof dskcnt) == -1)
perrexit();
dskloc = malloc(sizeof (struct dskinfo)*dskcnt);
if (dskloc == NULL)
perrexit();
}
#endif
#ifndef u370
/* construct tblmap and compute record size */
for (i=0;i<SINFO;i++){
#if pdp11 || vax
if (setup[i].n_value != 0){
if (i == GDS)
tblmap[i] = gdcnt * 8;
else {
if (i == RLS)
tblmap[i] = rlcnt;
else
tblmap[i] =iotbsz[i];
}
#endif
#ifdef u3b
if (setup[i].n_value != 0){
if (i == UN52)
tblmap[i] = un52cnt * 4;
else {
if (i == DSKINFO)
tblmap[i] = dskcnt;
else
tblmap[i] = iotbsz[i];
}
#endif
recsz += tblmap[i];
}
else
tblmap[i] = 0;
}
recsz = sizeof (struct sa) - sizeof d.devio + recsz * sizeof d.devio[0];
#endif
#ifdef u370
/* assign record size */
recsz = sizeof (struct sa);
#endif
if (argc == 3 || argc == 1){
/* no data file is specified, direct data to stdout */
fp = 1;
/* write header record */
write(fp,tblmap,sizeof tblmap);
}
else {
fname = argc==2? argv[1]: argv[3];
/* check if the data file is there */
/* check if data file is too old */
if ((stat(fname,&buf) == -1) ||
((min - buf.st_mtime) > 86400))
goto credfl;
if ((fp = open(fname,2)) == -1){
credfl:
/* data file does not exist:
create one and write the header record. */
if ((fp = creat(fname,00644)) == -1)
perrexit();
close(fp);
fp = open (fname,2);
lseek(fp,0L,0);
write (fp,tblmap,sizeof tblmap);
}
else{
/* data file exist:
position the write pointer to the last good recoed. */
lseek(fp,-(long)((buf.st_size - sizeof tblmap) % recsz),2);
}
}
/* if n =0 , write the additional dummy record */
if (ct == 0){
for (i=0;i<4;i++)
d.si.cpu[i] = -300;
d.ts = min;
write(fp,&d,recsz);
}
/* get memory for tables */
if(lseek(f,(long)setup[V].n_value,0) == -1)
perrexit();
if(read(f,&tbl,sizeof tbl) == -1)
perrexit();
if (tblloc < sizeof(struct inode)*tbl.v_inode)
tblloc =sizeof(struct inode)*tbl.v_inode;
if (tblloc < sizeof(struct file)*tbl.v_file)
tblloc = sizeof (struct file)*tbl.v_file;
if (tblloc < sizeof (struct proc)*tbl.v_proc)
tblloc = sizeof (struct proc)*tbl.v_proc;
if (tblloc < sizeof (struct text)*tbl.v_text)
tblloc = sizeof (struct text)*tbl.v_text;
loc = malloc(tblloc);
if (loc == NULL)
perrexit();
#ifdef u370
pxs = (struct pxs *)malloc(sizeof(*pxs));
stv = (struct stv *)malloc(sizeof(*stv));
#endif
for(;;) {
/* read data from /dev/kmem to structure d */
lseek(f,(long)setup[SINFO].n_value,0);
if (read(f, &d.si, sizeof d.si) == -1)
perrexit();
#if pdp11 || vax
d.si.bswapin = ctod(d.si.bswapin);
d.si.bswapout = ctod(d.si.bswapout);
for (i=HPS;i<SINFO;i++)
if (setup[i].n_value != 0){
lseek(f,(long)setup[i].n_value,0);
if (i<RLS){
if (read(f,ia[i],sizeof ia[i]) == -1)
perrexit();
}
else{
if (i == TSS){
if (read(f,id[i-TSS],sizeof id[i-TSS]) == -1)
perrexit();
}
else {
if (i == GDS){
if (read(f,ic[i-GDS],(sizeof (struct iotime)*gdcnt*8)) == -1)
perrexit();
}
else
if (read(f,ib[i-RLS],sizeof ib[i-RLS]) == -1)
perrexit();
}
}
}
#endif
#ifdef u3b
d.si.bswapin = ctob(d.si.bswapin)/BSIZE;
d.si.bswapout = ctob(d.si.bswapout)/BSIZE;
tapetbl(taploc);
dsktbl(dskloc);
#endif
#ifdef u370
if (read(sst, pxs, sizeof(*pxs)) == -1)
exit(2);
lseek(sst, 4096L, 0);
if (read(sst, stv, sizeof(*stv)) == -1)
exit(2);
lseek(sst, 0, 0);
/* Get performance statistics from tss sst tables */
/* Get cpu usage info */
d.nap = pxs->nap;
d.vmtm = stv->vmb;
d.usrtm = stv->nvmb;
d.usuptm = d.vmtm - d.usrtm;
d.idletm = stv->wtm1 + stv->wtm2;
d.ccv = stv->ccv;
/* Get scheduling info */
dp = stv->tsend.alt;
n = cvb(dp);
d.tsend = n;
d.intsched = stv->sched.kie;
d.mkdisp = stv->sched.kid;
/* Get drum and disk info */
for (i = 0; i < NDEV;i++) {
n = cvb(stv->dd[i].ddrs);
d.io[i].io_sread = n;
n = cvb(stv->dd[i].ddrp);
d.io[i].io_pread = n;
n = cvb(stv->dd[i].ddws);
d.io[i].io_swrite = n;
n = cvb(stv->dd[i].ddwp);
d.io[i].io_pwrite = n;
d.io[i].io_total = d.io[i].io_sread +
d.io[i].io_pread +
d.io[i].io_swrite +
d.io[i].io_pwrite;
}
d.elpstm = times(&buff);
d.curtm = time((long *) 0);
#endif
/* compute size of system table */
d.szinode = inodetbl(loc);
d.szfile = filetbl(loc);
d.sztext = texttbl(loc);
#ifndef u370
d.szproc = proctbl(loc);
#endif
#ifdef u370
proctbl(loc);
d.szproc = d.pi.sz;
#endif
/* record maximum sizes of system tables */
d.mszinode = tbl.v_inode;
d.mszfile = tbl.v_file;
d.msztext = tbl.v_text;
d.mszproc = tbl.v_proc;
/* record system tables overflows */
lseek(f,(long)setup[SERR].n_value,0);
if (read(f,&err,sizeof (struct syserr)) == -1)
perrexit();
d.inodeovf = err.inodeovf;
d.fileovf = err.fileovf;
d.textovf = err.textovf;
d.procovf = err.procovf;
/* get time stamp */
d.ts = time ((long *) 0);
i=0;
#ifndef u370
for (j=0;j<SINFO;j++){
#if pdp11 || vax
if (setup[j].n_value != 0){
for (k=0;k<tblmap[j];k++){
if (j == TSS){
d.devio[i][0] = id[j-TSS][k].io_cnt;
d.devio[i][1] = ctod(id[j-TSS][k].io_bcnt);
d.devio[i][2] = id[j-TSS][k].io_act;
d.devio[i][3] = id[j-TSS][k].io_resp;
}
else {
if (j == GDS){
d.devio[i][0] = ic[j-GDS][k].io_cnt;
d.devio[i][1] = ctod(ic[j-GDS][k].io_bcnt);
d.devio[i][2] = ic[j-GDS][k].io_act;
d.devio[i][3] = ic[j-GDS][k].io_resp;
}
else {
if (j >= RLS && j < GDS){
d.devio[i][0] = ib[j-RLS][k].io_cnt;
d.devio[i][1] = ctod(ib[j-RLS][k].io_bcnt);
d.devio[i][2] = ib[j-RLS][k].io_act;
d.devio[i][3] = ib[j-RLS][k].io_resp;
}
else{
d.devio[i][0] = ia[j][k].io_cnt;
d.devio[i][1] = ctod(ia[j][k].io_bcnt);
d.devio[i][2] = ia[j][k].io_act;
d.devio[i][3] = ia[j][k].io_resp;
}
}
}
i++;
}
#endif
#ifdef u3b
if (setup[j].n_value != 0){
if (j == UN52)
tapemv(taploc);
else
dskmv(dskloc);
#endif
}
}
#endif
/* write data to data file from structure d */
write(fp,&d,recsz);
if(--ct > 0)
sleep(ti);
else {
close(fp);
exit(0);
}
}
}
inodetbl(x)
register struct inode *x;
{
register i,n;
lseek(f,(long)setup[INO].n_value,0);
read(f,x,tbl.v_inode*sizeof(struct inode));
for (i=n=0;i<tbl.v_inode;i++,x++)
if (x->i_count != 0)
n++;
return(n);
}
filetbl(x)
register struct file *x;
{
register i,n;
lseek(f,(long)setup[FLE].n_value,0);
read(f,x,tbl.v_file*sizeof(struct file));
for (i=n=0;i<tbl.v_file; i++,x++)
if (x->f_count != 0)
n++;
return(n);
}
texttbl(x)
register struct text *x;
{
register i,n;
lseek(f,(long)setup[TXT].n_value,0);
read(f,x,tbl.v_text*sizeof(struct text));
for(i=n=0;i<tbl.v_text;i++,x++)
if (x->x_iptr != NULL)
n++;
return(n);
}
#ifndef u370
proctbl(x)
register struct proc *x;
{
register i,n;
lseek(f,(long)setup[PRO].n_value,0);
read (f,x,tbl.v_proc*sizeof(struct proc));
for (i=n=0;i<tbl.v_proc;i++,x++)
if(x->p_stat !=NULL)
n++;
return(n);
}
#endif
#ifdef u370
proctbl(x)
register struct proc *x;
{
register i;
/* reinitialize procinfo structure */
d.pi.sz = 0;
d.pi.run = 0;
d.pi.wtsem = 0;
d.pi.wtio = 0;
d.pi.wtsemtm = 0;
d.pi.wtiotm = 0;
lseek(f,(long)setup[PRO].n_value, 0);
read(f, x, tbl.v_proc*sizeof(struct proc));
for (i=0; i < tbl.v_proc; i++, x++){
if (x->p_stat == NULL)
continue;
d.pi.sz++;
if (x->p_stat == SRUN){
d.pi.run++;
continue;
}
else
if (x->p_stat == SSLEEP && x->p_ppid !=1)
if (x->p_wchan == 0) {
d.pi.wtio++;
d.pi.wtiotm += d.curtm - x->p_start;
}
else {
d.pi.wtsem++;
d.pi.wtsemtm += d.curtm - x->p_start;
}
}
/* The following prevents a 0 divide in sar -q */
if (d.pi.wtio == 0)
d.pi.wtio=1;
if (d.pi.wtsem == 0)
d.pi.wtsem=1;
return;
}
#endif
#ifdef u3b
tapetbl(x)
register struct un52 *x;
{
lseek (f,(long)setup[UN52].n_value,0);
read (f,x,un52cnt*sizeof (struct un52)*4);
return;
}
dsktbl(x)
register struct dskinfo *x;
{
register n;
lseek (f,(long)setup[DSKINFO].n_value,0);
read (f,x,dskcnt*sizeof (struct dskinfo));
return;
}
long tapemv(x)
register struct un52 *x;
{
register p;
for (p=0;p<un52cnt*4;p++,x++,i++){
d.devio[i][0] = x->iotime.ios.io_ops;
d.devio[i][1] = x->iotime.io_bcnt/BSIZE;
}
return ;
}
long dskmv(x)
register struct dskinfo *x;
{
register p;
for(p=0;p<dskcnt;p++,x++,i++){
d.devio[i][0] = x->devinfo.io_cnt;
d.devio[i][1] = x->devinfo.io_bcnt;
d.devio[i][2] = x->devinfo.io_act;
d.devio[i][3] = x->devinfo.io_resp;
}
return;
}
#endif
perrexit()
{
perror("sadc");
exit(2);
}