top hotplug memory support

Another patch from Jim for top to support hot-pluggable memory. Not
fully tested on real hot-pluggable memory because neither of us have
it
This commit is contained in:
Craig Small 2011-07-14 21:16:02 +10:00
parent 29b8775c39
commit a26c3bfa39
7 changed files with 131 additions and 87 deletions

View File

@ -13,7 +13,7 @@ global:
Hertz; smp_num_cpus; have_privs; getbtime;
sprint_uptime; uptime; user_from_uid; print_uptime; loadavg;
pretty_print_signals; print_given_signals; unix_print_signals; signal_name_to_number; signal_number_to_name;
meminfo; vminfo; getstat; getdiskstat; getpartitions_num; getslabinfo; get_pid_digits;
cpuinfo; meminfo; vminfo; getstat; getdiskstat; getpartitions_num; getslabinfo; get_pid_digits;
kb_active; kb_inactive; kb_main_buffers; kb_main_cached;
kb_main_free; kb_main_total; kb_main_used; kb_swap_free;
kb_swap_total; kb_swap_used; kb_main_shared;

View File

@ -24,9 +24,7 @@
#include <netinet/in.h> /* htons */
#endif
#ifndef OOMEM_ENABLE
long smp_num_cpus; /* number of CPUs */
#endif
#define BAD_OPEN_MESSAGE \
"Error: /proc must be mounted\n" \
@ -182,11 +180,7 @@ static void old_Hertz_hack(void){
setlocale(LC_NUMERIC, savelocale);
jiffies = user_j + nice_j + sys_j + other_j;
seconds = (up_1 + up_2) / 2;
#ifndef OOMEM_ENABLE
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus );
#else
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() );
#endif
/* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
switch(h){
case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */
@ -252,44 +246,13 @@ static int check_for_privs(void){
return !!rc;
}
#ifdef OOMEM_ENABLE
long smp_num_cpus(void)
{
static long _smp_num_cpus=-1; /* number of CPUs */
if (_smp_num_cpus != -1)
return(_smp_num_cpus);
// ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo
//
// SourceForge has an old Alpha running Linux 2.2.20 that
// appears to have a non-SMP kernel on a 2-way SMP box.
// _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512
// _SC_NPROCESSORS_ONLN returns 1, which should work OK
_smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(_smp_num_cpus<1) _smp_num_cpus=1; /* SPARC glibc is buggy */
return(_smp_num_cpus);
}
#endif
static void init_libproc(void) __attribute__((constructor));
static void init_libproc(void){
have_privs = check_for_privs();
init_Linux_version(); /* Must be called before we check code */
#ifndef OOMEM_ENABLE
// ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo
//
// SourceForge has an old Alpha running Linux 2.2.20 that
// appears to have a non-SMP kernel on a 2-way SMP box.
// _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512
// _SC_NPROCESSORS_ONLN returns 1, which should work OK
smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(smp_num_cpus<1) smp_num_cpus=1; /* SPARC glibc is buggy */
#endif
cpuinfo();
if(linux_version_code > LINUX_VERSION(2, 4, 0)){
Hertz = find_elf_note(AT_CLKTCK);
if(Hertz!=NOTE_NOT_FOUND) return;
@ -978,3 +941,19 @@ unsigned get_pid_digits(void){
out:
return ret;
}
///////////////////////////////////////////////////////////////////////////
void cpuinfo (void) {
// ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo
//
// SourceForge has an old Alpha running Linux 2.2.20 that
// appears to have a non-SMP kernel on a 2-way SMP box.
// _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512
// _SC_NPROCESSORS_ONLN returns 1, which should work OK
smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if (smp_num_cpus<1) /* SPARC glibc is buggy */
smp_num_cpus=1;
}

View File

@ -7,12 +7,8 @@
EXTERN_C_BEGIN
extern unsigned long long Hertz; /* clock tick frequency */
#ifndef OOMEM_ENABLE
extern long smp_num_cpus; /* number of CPUs */
#else
extern long smp_num_cpus(void); /* number of CPUs */
#endif
extern int have_privs; /* boolean, true if setuid or similar */
extern long smp_num_cpus; /* number of CPUs */
extern int have_privs; /* boolean, true if setuid or similar */
#if 0
#define JT double
@ -136,5 +132,7 @@ extern unsigned int getslabinfo (struct slab_cache**);
extern unsigned get_pid_digits(void) FUNCTION;
extern void cpuinfo (void);
EXTERN_C_END
#endif /* SYSINFO_H */

10
top.1
View File

@ -59,9 +59,9 @@
.ds FM full\-screen mode
.ds KA arrow key
.ds KS scrolling key
.ds MP \fBphysical\fR memory
.ds MS \fBshared\fR memory
.ds MV \fBvirtual\fR memory
.ds MP physical memory
.ds MS shared memory
.ds MV virtual memory
.ds NT \fBNote\fR:
.ds PU CPU
.ds Pu cpu
@ -775,9 +775,9 @@ line.
.TP 7
\ \ \<\fBEnter\fR> or <\fBSpace\fR> :\fIRefresh-Display \fR
These commands do nothing, they are simply ignored.
However, they will awaken \*(We and following receipt of any input
These commands awaken \*(We and following receipt of any input
the entire display will be repainted.
They also force an update of any hotplugged \*(Pu or \*(MP changes.
Use either of these keys if you have a large delay interval and wish
to see current status,

51
top.c
View File

@ -1679,7 +1679,7 @@ static void zap_fieldstab (void) {
Cpu_pmax = 99.0;
Fieldstab[P_CPU].fmts = "%#4.1f ";
if (Rc.mode_irixps && Cpu_tot > 1 && !Thread_mode) {
if (Rc.mode_irixps && Cpu_tot > 1 && !Thread_mode) {
Cpu_pmax = 9999.0;
Fieldstab[P_CPU].fmts = "%4.0f ";
}
@ -1696,13 +1696,13 @@ static void zap_fieldstab (void) {
static CPU_t *cpus_refresh (CPU_t *cpus) {
static const char err_read[] = "failed /proc/stat read";
static FILE *fp = NULL;
static int smp_sav = -1;
static int sav_cpus = -1;
char buf[MEDBUFSIZ]; // enough for /proc/stat CPU line (not the intr line)
int i;
/*** hotplug_acclimated ***/
if (smp_sav != SMP_NUM_CPUS) {
Cpu_tot = smp_sav = SMP_NUM_CPUS;
if (sav_cpus != smp_num_cpus) {
Cpu_tot = sav_cpus = smp_num_cpus;
zap_fieldstab();
calibrate_fields();
if (fp) { fclose(fp); fp = NULL; }
@ -2000,11 +2000,38 @@ static proc_t **procs_refresh (proc_t **ppt) {
#undef PTRsz
#undef ENTsz
} // end: procs_refresh
/*
* This serves as our interface to the memory & cpu count (sysinfo)
* portion of libproc. In support of those hotpluggable resources,
* the sampling frequencies are reduced so as to minimize overhead.
* We'll strive to verify the number of cpus every 5 minutes and the
* memory availability/usage every 3 seconds. */
static void sysinfo_refresh (int forced) {
static time_t mem_secs, cpu_secs;
time_t cur_secs;
if (forced)
mem_secs = cpu_secs = 0;
time(&cur_secs);
if (3 <= cur_secs - mem_secs) {
meminfo();
mem_secs = cur_secs;
}
#ifndef PRETEND4CPUS
if (300 <= cur_secs - cpu_secs) {
cpuinfo();
cpu_secs = cur_secs;
}
#endif
} // end: sysinfo_refresh
/*###### Startup routines ##############################################*/
/*
* No mater what *they* say, we handle the really really BIG and
* No matter what *they* say, we handle the really really BIG and
* IMPORTANT stuff upon which all those lessor functions depend! */
static void before (char *me) {
int i;
@ -2015,10 +2042,9 @@ static void before (char *me) {
// establish cpu particulars -- even bigger!
#ifdef PRETEND4CPUS
SMP_NUM_CPUS = Cpu_tot = 4;
#else
Cpu_tot = SMP_NUM_CPUS;
smp_num_cpus = 4;
#endif
Cpu_tot = smp_num_cpus;
if (linux_version_code > LINUX_VERSION(2, 5, 41))
Cpu_States_fmts = STATES_line2x5;
if (linux_version_code >= LINUX_VERSION(2, 6, 0))
@ -2081,6 +2107,7 @@ static void configs_read (void) {
fbuf[0] = '\0';
fgets(fbuf, sizeof(fbuf), fp); // sys rc file, line 2
sscanf(fbuf, "%f", &Rc.delay_time);
fclose(fp);
}
fp = fopen(Rc_name, "r");
@ -3009,7 +3036,8 @@ static void do_key (int ch) {
help_view();
break;
case kbd_ENTER: // these two will have the effect of waking us
case kbd_SPACE: // from 'select()' then refreshing the display
case kbd_SPACE: // from 'select()', updating hotplugged resources
sysinfo_refresh(1); // and then refreshing the display
break;
default: // and now, the real work...
for (i = 0; i < MAXTBL(key_tab); ++i)
@ -3110,14 +3138,14 @@ static proc_t **summary_show (void) {
// whoa first time, gotta' prime the pump...
if (!p_table) {
struct timeval tv = { 0, 300000 };
p_table = procs_refresh(NULL);
putp(Cap_clr_scr);
select(0, NULL, NULL, NULL, &tv); // sleep for a bit...
usleep(LIB_USLEEP);
} else
putp(Batch ? "\n\n" : Cap_home);
p_table = procs_refresh(p_table);
sysinfo_refresh(0);
// Display Uptime and Loadavg
if (isROOM(View_LOADAV, 1)) {
@ -3157,7 +3185,6 @@ static proc_t **summary_show (void) {
}
// Display Memory and Swap stats
meminfo();
if (isROOM(View_MEMORY, 2)) {
#define mkM(x) (unsigned long)(kb_main_ ## x >> shift)
#define mkS(x) (unsigned long)(kb_swap_ ## x >> shift)

17
top.h
View File

@ -62,23 +62,16 @@
#define STRSORTCMP strcmp
#endif
#ifdef OOMEM_ENABLE
/* FIXME: perhaps making this a function in the suse version of
sysinfo.c was a prelude to hotpluggable updates -- unfortunately,
the return value is invariant as currently implemented! */
#define SMP_NUM_CPUS smp_num_cpus()
#else
#define SMP_NUM_CPUS smp_num_cpus
#endif
/*###### Some Miscellaneous constants ##################################*/
/* The default delay twix updates */
#define DEF_DELAY 3.0
/* Length of time a 'message' is displayed (in microseconds) */
/* Length of time a message is displayed and the duration
of a 'priming' wait during library startup (in microseconds) */
#define MSG_USLEEP (useconds_t)1250000
#define LIB_USLEEP (useconds_t)150000
/* Specific process id monitoring support (command line only) */
#define MONPIDMAX 20
@ -592,9 +585,6 @@ typedef struct WIN_t {
#if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH)
# error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH'
#endif
#if defined(PRETEND4CPUS) && defined (OOMEM_ENABLE)
# error 'PRETEND4CPUS' conflicts with 'OOMEM_ENABLE'
#endif
#if (LRGBUFSIZ < SCREENMAX)
# error 'LRGBUFSIZ' must NOT be less than 'SCREENMAX'
#endif
@ -655,6 +645,7 @@ typedef struct WIN_t {
#endif
//atic void prochlp (proc_t *p);
//atic proc_t **procs_refresh (proc_t **ppt);
//atic void sysinfo_refresh (int forced);
/*------ Startup routines ----------------------------------------------*/
//atic void before (char *me);
//atic void configs_read (void);

69
w.c
View File

@ -29,6 +29,7 @@
#include <utmp.h>
#include <locale.h>
#include <termios.h>
#include <arpa/inet.h>
static int ignoreuser = 0; /* for '-u' */
static proc_t **procs; /* our snapshot of the process table */
@ -44,6 +45,7 @@ typedef struct utmp utmp_t;
/* Uh... same thing as UT_NAMESIZE */
#define USERSZ (sizeof u->ut_user)
#define MAX_FROM_LEN 16
/* This routine is careful since some programs leave utmp strings
* unprintable. Always outputs at least 16 chars padded with spaces
@ -57,7 +59,7 @@ static void print_host(const char *restrict host, int len) {
/* for now, we'll just limit it to the 16 that the libc5 version
* of utmp uses.
*/
if (len > 16) len = 16;
if (len > MAX_FROM_LEN) len = MAX_FROM_LEN;
last = host + len;
for ( ; host < last ; host++){
if (isprint(*host) && *host != ' ') {
@ -67,8 +69,45 @@ static void print_host(const char *restrict host, int len) {
break;
}
}
// space-fill, and a '-' too if needed to ensure the column exists
if(width < 16) fputs("- "+width, stdout);
/* space-fill, and a '-' too if needed to ensure the column exists */
if(width < MAX_FROM_LEN) fputs("- "+width, stdout);
}
/* This routine prints either the hostname or the IP address of the remote */
static void print_from(const utmp_t *restrict const u, int ip_addresses) {
char buf[MAX_FROM_LEN + 1];
char buf_ipv6[INET6_ADDRSTRLEN];
int len;
int32_t ut_addr_v6[4]; /* IP address of remote host. */
if (ip_addresses) { /* -n switch used */
memcpy(&ut_addr_v6, &u->ut_addr_v6, sizeof(ut_addr_v6));
if (IN6_IS_ADDR_V4MAPPED(&ut_addr_v6)) {
/* map back */
ut_addr_v6[0] = ut_addr_v6[3];
ut_addr_v6[1] = 0;
ut_addr_v6[2] = 0;
ut_addr_v6[3] = 0;
}
if (ut_addr_v6[1] || ut_addr_v6[2] || ut_addr_v6[3]) {
/* IPv6 */
if (!inet_ntop(AF_INET6, &ut_addr_v6, buf_ipv6, sizeof(buf_ipv6))) {
snprintf(buf_ipv6, INET6_ADDRSTRLEN, "?");
}
strncpy(buf, buf_ipv6, MAX_FROM_LEN);
} else {
/* IPv4 */
if (!inet_ntop(AF_INET, &ut_addr_v6[0], buf, sizeof(buf))) {
snprintf(buf, MAX_FROM_LEN, "?");
}
}
buf[MAX_FROM_LEN] = 0;
for (len = strlen(buf); len < MAX_FROM_LEN; len++) buf[len]=' ';
buf[MAX_FROM_LEN] = 0;
fputs(buf, stdout);
} else {
print_host(u->ut_host, sizeof u->ut_host);
}
}
/***** compact 7 char format for time intervals (belongs in libproc?) */
@ -169,7 +208,7 @@ static const proc_t *getproc(const utmp_t *restrict const u, const char *restric
/***** showinfo */
static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) {
static void showinfo(utmp_t *u, int formtype, int maxcmd, int from, int ip_addresses) {
unsigned long long jcpu;
int ut_pid_found;
unsigned i;
@ -196,7 +235,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) {
if (formtype) {
printf("%-9.8s%-9.8s", uname, u->ut_line);
if (from)
print_host(u->ut_host, sizeof u->ut_host);
print_from(u, ip_addresses);
print_logintime(u->ut_time, stdout);
if (*u->ut_line == ':') /* idle unknown for xdm logins */
printf(" ?xdm? ");
@ -211,7 +250,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) {
} else {
printf("%-9.8s%-9.8s", u->ut_user, u->ut_line);
if (from)
print_host(u->ut_host, sizeof u->ut_host);
print_from(u, ip_addresses);
if (*u->ut_line == ':') /* idle unknown for xdm logins */
printf(" ?xdm? ");
else
@ -233,14 +272,22 @@ int main(int argc, char **argv) {
char *user = NULL;
utmp_t *u;
struct winsize win;
int header=1, longform=1, from=1, args, maxcmd=80, ch;
int args;
int maxcmd = 80;
int ch;
/* defaults */
int header = 1;
int longform = 1;
int from = 1;
int ip_addresses = 0;
#ifndef W_SHOWFROM
from = 0;
#endif
setlocale(LC_ALL, "");
for (args=0; (ch = getopt(argc, argv, "hlusfV")) != EOF; args++)
for (args=0; (ch = getopt(argc, argv, "hlusfnV")) != EOF; args++)
switch (ch) {
case 'h': header = 0; break;
case 'l': longform = 1; break;
@ -248,6 +295,7 @@ int main(int argc, char **argv) {
case 'f': from = !from; break;
case 'V': display_version(); exit(0);
case 'u': ignoreuser = 1; break;
case 'n': ip_addresses = 1; break;
default:
printf("usage: w -hlsufV [user]\n"
" -h skip header\n"
@ -255,6 +303,7 @@ int main(int argc, char **argv) {
" -s short listing\n"
" -u ignore uid of processes\n"
" -f toggle FROM field (default %s)\n"
" -n use IP addresses instead of hostname\n"
" -V display version\n", FROM_STRING);
exit(1);
}
@ -292,14 +341,14 @@ int main(int argc, char **argv) {
u = getutent();
if (unlikely(!u)) break;
if (u->ut_type != USER_PROCESS) continue;
if (!strncmp(u->ut_user, user, USERSZ)) showinfo(u, longform, maxcmd, from);
if (!strncmp(u->ut_user, user, USERSZ)) showinfo(u, longform, maxcmd, from, ip_addresses);
}
} else {
for (;;) {
u = getutent();
if (unlikely(!u)) break;
if (u->ut_type != USER_PROCESS) continue;
if (*u->ut_user) showinfo(u, longform, maxcmd, from);
if (*u->ut_user) showinfo(u, longform, maxcmd, from, ip_addresses);
}
}
endutent();