/*
* pg_top - a top PostgreSQL users display for Unix
*
* SYNOPSIS: For FreeBSD-2.x, 3.x, 4.x, and 5.x
*
* DESCRIPTION:
* Originally written for BSD4.4 system by Christos Zoulas.
* Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
* Order support hacked in from top-3.5beta6/machine/m_aix41.c
* by Monte Mitzelfelt
* Ported to FreeBSD 5.x by William LeFebvre
*
* AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
* Steven Wallace <swallace@freebsd.org>
* Wolfram Schneider <wosch@FreeBSD.org>
*/
#include <sys/time.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <err.h>
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <nlist.h>
#include <math.h>
#include <kvm.h>
#include <pwd.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/dkstat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/vmmeter.h>
#include <sys/resource.h>
#include <sys/rtprio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/* Swap */
#include <stdlib.h>
#include <sys/conf.h>
#include <osreldate.h> /* for changes in kernel structures */
#include "pg_top.h"
#include "machine.h"
#include "utils.h"
#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
static int getkval __P((unsigned long, int *, int, char *));
extern char *printable __P((char *));
static void getsysctl(const char *name, void *ptr, size_t len);
int swapmode __P((int *retavail, int *retfree));
static int maxcpu;
static int maxid;
static int ncpus;
static u_long cpumask;
static long *times;
static long *pcpu_cp_time;
static long *pcpu_cp_old;
static long *pcpu_cp_diff;
static int64_t * pcpu_cpu_states;
static int smpmode;
static int namelength;
static int cmdlength;
/* get_process_info passes back a handle. This is what it looks like: */
struct handle
{
struct kinfo_proc **next_proc; /* points to next valid proc pointer */
int remaining; /* number of pointers remaining */
};
/* declarations for load_avg */
#include "loadavg.h"
/* macros to access process information */
#if OSMAJOR <= 4
#define PP(pp, field) ((pp)->kp_proc . p_##field)
#define EP(pp, field) ((pp)->kp_eproc . e_##field)
#define VP(pp, field) ((pp)->kp_eproc.e_vm . vm_##field)
#define PRUID(pp) ((pp)->kp_eproc.e_pcred.p_ruid)
#else
#define PP(pp, field) ((pp)->ki_##field)
#define VP(pp, field) ((pp)->ki_##field)
#define PRUID(pp) ((pp)->ki_ruid)
#endif
/* what we consider to be process size: */
#if OSMAJOR <= 4
#define PROCSIZE(pp) (VP((pp), map.size) / 1024)
#else
#define PROCSIZE(pp) (((pp)->ki_size) / 1024)
#endif
/* for 5.x and higher we show thread count */
#if OSMAJOR >= 5
#define SHOW_THREADS
#endif
/* definitions for indices in the nlist array */
static struct nlist nlst[] = {
#define X_CCPU 0
{"_ccpu"},
#define X_CP_TIME 1
{"_cp_time"},
#define X_AVENRUN 2
{"_averunnable"},
#define X_BUFSPACE 3
{"_bufspace"}, /* K in buffer cache */
#define X_CNT 4
{"_cnt"}, /* struct vmmeter cnt */
/* Last pid */
#define X_LASTPID 5
{"_nextpid"},
#define X_BOOTTIME 6
{"_boottime"},
{0}
};
/*
* These definitions control the format of the per-process area
*/
#ifdef SHOW_THREADS
static char smp_header[] =
" PID %-*.*s THR PRI NICE SIZE RES STATE C TIME CPU COMMAND";
#define smp_Proc_format \
"%5d %-*.*s %3d %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %s"
static char up_header[] =
" PID %-*.*s THR PRI NICE SIZE RES STATE TIME CPU COMMAND";
#define up_Proc_format \
"%5d %-*.*s %3d %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %s"
#else
static char smp_header[] =
" PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND";
#define smp_Proc_format \
"%5d %-*.*s %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %s"
static char up_header[] =
" PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
#define up_Proc_format \
"%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %s"
/* define what weighted cpu is. */
#define weighted_cpu(pct, pp) (PP((pp), swtime) == 0 ? 0.0 : \
((pct) / (1.0 - exp(PP((pp), swtime) * logcpu))))
#endif
/* process state names for the "STATE" column of the display */
/* the extra nulls in the string "run" are for adding a slash and
the processor number when needed */
char *state_abbrev[] =
{
"", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB",
};
static kvm_t * kd;
/* values that we stash away in _init and use in later routines */
static double logcpu;
/* these are retrieved from the kernel in _init */
static load_avg ccpu;
/* these are offsets obtained via nlist and used in the get_ functions */
static unsigned long cp_time_offset;
static unsigned long avenrun_offset;
static unsigned long lastpid_offset;
static int lastpid;
static unsigned long cnt_offset;
static unsigned long bufspace_offset;
/* these are for calculating cpu state percentages */
static int64_t cp_time[CPUSTATES];
static int64_t cp_old[CPUSTATES];
static int64_t cp_diff[CPUSTATES];
/* these are for detailing the process states */
int process_states[6];
/* these are for detailing the cpu states */
int64_t cpu_states[CPUSTATES];
char *cpustatenames[] = {
"user", "nice", "system", "interrupt", "idle", NULL
};
/* these are for detailing the memory statistics */
long