/*
* pg_top - a top PostgreSQL users display for Unix
*
* SYNOPSIS: Any SGI machine running IRIX 6.2 and up
*
* DESCRIPTION:
* This is the machine-dependent module for IRIX as supplied by
* engineers at SGI.
*
* CFLAGS: -DHAVE_GETOPT -D_OLD_TERMIOS -DORDER
*
* AUTHOR: Sandeep Cariapa <cariapa@sgi.com>
* AUTHOR: Larry McVoy <lm@sgi.com>
* Sandeep did all the hard work; I ported to 6.2 and fixed up some formats.
* AUTHOR: John Schimmel <jes@sgi.com>
* He did the all irix merge.
* AUTHOR: Ariel Faigon <ariel@sgi.com>
* Ported to Ficus/Kudzu (IRIX 6.4+).
* Got rid of all nlist and different (elf64, elf32, COFF) kernel
* dependencies
* Various small fixes and enhancements: multiple CPUs, nicer formats.
* Added -DORDER process display ordering
* cleaned most -fullwarn'ings.
* Need -D_OLD_TERMIOS when compiling on IRIX 6.4 to work on 6.2 systems
* Support much bigger values in memory sizes (over Peta-byte)
* AUTHOR: William LeFebvre
* Converted to ANSI C and updated to new module interface
*/
#define _KMEMUSER
#include "config.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/sysinfo.h>
#include <sys/sysmp.h>
#include <sys/utsname.h>
#include <sys/schedctl.h> /* for < 6.4 NDPHIMAX et al. */
#include <paths.h>
#include <assert.h>
#include <values.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include "pg_top.h"
#include "machine.h"
#include "utils.h"
#define KMEM "/dev/kmem"
typedef double load_avg;
#define loaddouble(la) (la)
#define intload(i) ((double)(i))
/*
* Structure for keeping track of CPU times from last time around
* the program. We keep these things in a hash table, which is
* recreated at every cycle.
*/
struct oldproc
{
pid_t oldpid;
double oldtime;
double oldpct;
};
static int oldprocs; /* size of table */
static struct oldproc *oldbase;
#define HASH(x) ((x << 1) % oldprocs)
#define pagetok(pages) ((((uint64_t) pages) * pagesize) >> 10)
/*
* Ugly hack, save space and complexity of allocating and maintaining
* parallel arrays to the prpsinfo array: use spare space (pr_fill area)
* in prpsinfo structures to store %CPU calculated values
*/
#define D_align(addr) (((unsigned long)(addr) & ~0x0fU))
#define percent_cpu(pp) (* (double *) D_align(&((pp)->pr_fill[0])))
#define weighted_cpu(pp) (* (double *) D_align(&((pp)->pr_fill[4])))
/* Username field to fill in starts at: */
#define UNAME_START 16
/*
* These definitions control the format of the per-process area
*/
static char header[] =
" PID PGRP X PRI SIZE RES STATE TIME %WCPU %CPU COMMAND";
/*
012345678901234567890123456789012345678901234567890123456789012345678901234567
10 20 30 40 50 60 70
*/
/* PID PGRP USER PRI SIZE RES STATE TIME %WCPU %CPU CMD */
#define Proc_format \
"%7d %7d %-8.8s %4.4s %6.6s %5.5s %-6.6s %6.6s %5.2f %5.2f %-.10s"
/*
* these are for detailing the cpu states
* Data is taken from the sysinfo structure (see <sys/sysinfo.h>)
* We rely on the following values:
*
* #define CPU_IDLE 0
* #define CPU_USER 1
* #define CPU_KERNEL 2
* #define CPU_WAIT 3
* #define CPU_SXBRK 4
* #define CPU_INTR 5
*/
#ifndef CPU_STATES /* defined only in 6.4 and up */
#define CPU_STATES 6
#endif
int cpu_states[CPU_STATES];
char *cpustatenames[] = {
"idle", "usr", "ker", "wait", "xbrk", "intr",
NULL
};
/* these are for detailing the memory statistics */
#define MEMSTATS 10
int memory_stats[MEMSTATS];
char *memorynames[] = {
"K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
};
char uname_str[40];
double load[3];
static char fmt[MAX_COLS + 2];
int numcpus;
/* useful externals */
extern int errno;
extern char *sys_errlist[];
extern char *myname;
extern char *format_k();
extern char *format_time();
extern long percentages();
static int kmem;
static unsigned long avenrun_offset;
static float irix_ver; /* for easy numeric comparison */
static struct prpsinfo *pbase;
static struct prpsinfo **pref;
static struct oldproc *oldbase;
static int oldprocs; /* size of table */
static DIR *procdir;
static int ptable_size; /* allocated process table size */
static int nproc; /* estimated process table size */
static int pagesize;
/* get_process_info passes back a handle. This is what it looks like: */
struct handle
{
struct prpsinfo **next_proc; /* points to next valid proc pointer */
int remaining; /* number of pointers remaining */
};
static struct handle handle;
void getptable(struct prpsinfo * baseptr);
void size(int fd, struct prpsinfo * ps);
extern char *ordernames[];
/*
* Process states letters are mapped into numbers
* 6.5 seems to have changed the semantics of prpsinfo.pr_state
* so we rely, (like ps does) on the char value pr_sname.
* The order we use here is what may be most interesting