SMP fix, speed, hide IO-wait, dumb/VT510 terms

This commit is contained in:
albert 2002-10-18 21:07:49 +00:00
parent 33023bbf34
commit 80a7f3ff35
5 changed files with 199 additions and 180 deletions

View File

@ -171,7 +171,7 @@ Thanks.
read those lines | case 5: case 6: case 7: case:
from the LEFT to | cap = Curwin->captab[(int:
the RIGHT? This | *sub_end = '\0'; :
"innovation" may | printf("%s%.*s%s", cap, r:
"innovation" may | PUTP("%s%.*s%s", cap, roo:
possibly benefit | room -= (sub_end - sub_be:
those particular | sub_beg = ++sub_end; :
kinds of people, | break; :
@ -241,9 +241,11 @@ Enjoy...
//#define CASEUP_SCALE /* show scaled time/num suffix upper case */
//#define CASEUP_SUMMK /* show memory summary kilobytes with 'K' */
//#define POSIX_CMDLIN /* use '[ ]' for kernel threads, not '( )' */
//#define PRETEND2_5_X /* pretend we're linux 2.5.x (for IO-wait) */
//#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */
//#define PRETENDNOCAP /* use a terminal without essential caps */
//#define SORT_SUPRESS /* *attempt* to reduce qsort overhead */
//#define USE_LIB_STA3 /* use lib status (3 ch) vs. proc_t (1 ch) */
//#define YIELDCPU_OFF /* hang on tight, DON'T issue sched_yield */
//#define WARN_NOT_SMP /* restrict '1' & 'I' commands to true smp */

View File

@ -405,10 +405,10 @@ static int pr_fname(void){
/* elapsed wall clock time, [[dd-]hh:]mm:ss format (not same as "time") */
static int pr_etime(void){
unsigned long long t;
unsigned long t;
unsigned dd,hh,mm,ss;
char *cp = outbuf;
t = seconds_since_boot - pp->start_time / Hertz;
t = seconds_since_boot - (unsigned long)(pp->start_time / Hertz);
ss = t%60;
t /= 60;
mm = t%60;
@ -475,7 +475,7 @@ static int pr_ppid(void){
/* cumulative CPU time, [dd-]hh:mm:ss format (not same as "etime") */
static int pr_time(void){
unsigned long long t;
unsigned long t;
unsigned dd,hh,mm,ss;
int c;
t = (pp->utime + pp->stime) / Hertz;

37
top.1
View File

@ -147,7 +147,6 @@ and used when reading and writing a \*(CF.
.\" ----------------------------------------------------------------------
.SH 0. OVERVIEW, Documentation and Operation
.\" ----------------------------------------------------------------------
.Scr
Listed below are the remaining topics in this document.
Be advised that none of these topics need be read now, or studied later,
for a successful\fB close-encounter-of-the-1st-kind\fR with \*(Us.
@ -155,9 +154,9 @@ for a successful\fB close-encounter-of-the-1st-kind\fR with \*(Us.
You need remember just the\fB help key\fR ('h' or '?') to survive
\*(EM nay, prosper!
What about quitting, you ask?
Well, of course there's the 'q' \*(CI, but then \*(Me does quite well
Well, of course there's the 'q' \*(CI, but \*(Me does quite well
with\fB signals\fR.
So just zap him with the traditional \fI^C\fR when you're done.
So just zap him with a \fI^C\fR when you're done.
.br
Oh, almost forgot...
@ -189,7 +188,7 @@ Remaining Table of Contents
a. SYSTEM Configuration File
b. PERSONAL Configuration File
6.\fB DIFFERENCES / New Features\fR
a. User Interface Etiquette
a. Interface Etiquette
b. Expanded Configurable Display Support
c. Enhanced Field/Column Management
d. Customization Flexibility
@ -200,14 +199,15 @@ Remaining Table of Contents
lastly,\fB the usual\fR...
8. BUGS, 9. HISTORY Former top, 10. AUTHOR, 11. SEE ALSO
.Scr
.PP
When you start \*(Us for the first time, you'll be presented with the
traditional screen elements: 1) Summary Area; 2) Message/Prompt Line;
3) Columns Header; 4) Task Area.
But even out-of-the-box, there are numerous subtle differences, compared to
the former top.
.SS Highlighting
.TP 3
.B Highlighting
.I Summary_Area\fR:
It's retina-friendly with\fB no\fR highlighting for load/uptime and
only\fB values\fR highlighted for other elements.
@ -216,9 +216,10 @@ only\fB values\fR highlighted for other elements.
Tasks\fB running\fR (or ready to run) will be highlighted, and bold is
only one way of emphasizing such processes.
.SS Content/Labels
.TP 3
.B Content/Labels
.I Summary_Area\fR:
The program\fB name\fR is shown (symlinks/aliases, remember?).
The program\fB name\fR is shown (perhaps a symlink/alias).
The Cpu\fI(s)\fR state\fR\fB label\fR hints at other possibilities (smp folks,
stand by).
The\fB memory\fR stats use a lower case '\fBk\fR' (making numbers and letters
@ -228,7 +229,7 @@ more distinct).
Shows a\fB new\fR field and some\fB changed\fR labels (unseen to the right).
Precious horizontal space is no longer squandered.
.Scr
.PP
All of that, however, is just the tip of the old iceberg.
So please, do not touch that dial!
You may, however, peruse the following screen representation before we
@ -263,7 +264,7 @@ acknowledge \*(Us's default settings ...
+\fB--------------------------------------\fR+
.Rje
.Scr
.PP
Within the following categories, \*(Us's startup defaults are documented
assuming no \*(CF, thus no user customizations.
However, items shown with an \*(AS could be overridden through the\fB
@ -1436,12 +1437,14 @@ personal \*(CF to the current directory, subject to permissions.
.SH 6. DIFFERENCES / New Features
.\" ----------------------------------------------------------------------
The following summarizes differences between \*(US and your former \*(Me.
It was based on procps-2.0.7.
It was originally based on procps-2.0.7.
However, except for the separate/summary \*(PU toggle, all of these
differences also apply through procps-2.0.10.
.\" ......................................................................
.SS 6a. User Interface Etiquette
.SS 6a. Interface Etiquette
.New
Input and output are more carefully implemented.
Input and output are far more carefully implemented in \*(Us.
You won't be subjected to 4 - 5 'Unknown command' messages should you press the
wrong key.
@ -1457,11 +1460,15 @@ The Help screen will no longer overflow, even when running with a
The fields selection/ordering screens do not carelessly destroy important
information through unintended line wraps.
.New
Should you narrow a xterm window to less than 80 columns while \*(Us is
running, you will not be left with an utterly worthless, embarrassing display.
.\" ......................................................................
.SS 6b. Expanded Configurable Display Support
.New
With \*(Us, you can alternate between a\fB summary\fR display or one
showing\fB each \*(Pu\fR separately.
In an SMP environment, you can choose between a\fB summary\fR display or
you may show\fB each \*(Pu\fR separately.
No longer must this choice be irrevocably made at startup.
.New

290
top.c
View File

@ -23,6 +23,9 @@
#include <ctype.h>
#include <curses.h>
#include <errno.h>
#ifndef YIELDCPU_OFF
#include <sched.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@ -58,7 +61,7 @@
#endif
/* need: meminfo stuff */
#include "proc/sysinfo.h"
/* need: procps_version */
/* need: procps_version + kernel version stuff */
#include "proc/version.h"
/* need: sprint_uptime */
#include "proc/whattime.h"
@ -84,9 +87,11 @@ static int Page_size;
static unsigned Mem_pages;
#endif
/* SMP and Irix/Solaris mode support */
/* SMP, Irix/Solaris mode, Linux 2.5.xx support */
static int Cpu_tot,
*Cpu_map;
/* assume no IO-wait stats, overridden if linux 2.5.41 */
static char *States_fmts = STATES_line2x4;
/* Specific process id monitoring support */
static pid_t Monpids [MONPIDMAX] = { 0 };
@ -151,7 +156,7 @@ static WIN_t *Winstk [GROUPSMAX],
and/or that would be too cumbersome managed as parms */
static int Frame_maxtask; /* last known number of active tasks */
/* ie. current 'size' of proc table */
static float Frame_scale; /* so we can '*' vs. '/' IF 'pcpu' */
static float Frame_tscale; /* so we can '*' vs. '/' WHEN 'pcpu' */
static int Frame_srtflg, /* the subject window sort direction */
Frame_ctimes, /* the subject window's ctimes flag */
Frame_cmdlin; /* the subject window's cmdlin flag */
@ -230,7 +235,7 @@ _SC_NUM1(P_FLG, flags)
/*###### Tiny useful routine(s) ########################################*/
/*
* This routine isolates ALL user input and ensures that we
* This routine isolates ALL user INPUT and ensures that we
* wont be mixing I/O from stdio and low-level read() requests */
static int chin (int ech, char *buf, unsigned cnt)
{
@ -306,12 +311,15 @@ static void bye_bye (int eno, const char *str)
#endif
if (!Batch)
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
printf("%s%s\n", tg2(0, Screen_rows), Cap_curs_norm);
putp(tg2(0, Screen_rows));
putp(Cap_curs_norm);
putp("\n");
#ifdef ATEOJ_REPORT
fprintf(stderr,
"\nbye_bye's Summary report:"
"\n\tProgram"
"\n\t Linux version = %u.%u.%u"
"\n\t Page_size = %d, Cpu_tot = %d"
"\n\t %s, using Hertz = %u (%u bytes, %u-bit time)"
"\n\t sizeof(CPUS_t) = %u, sizeof(HIST_t) = %u (%u HIST_t's/Page)"
@ -335,6 +343,9 @@ static void bye_bye (int eno, const char *str)
"\n\t winlines = %d, maxtasks = %d, maxcmdln = %d"
"\n\t sortindx = %d"
"\n"
, LINUX_VERSION_MAJOR(linux_version_code)
, LINUX_VERSION_MINOR(linux_version_code)
, LINUX_VERSION_PATCH(linux_version_code)
, Page_size, Cpu_tot
, procps_version, (unsigned)Hertz, sizeof(Hertz), sizeof(Hertz) * 8
, sizeof(CPUS_t), sizeof(HIST_t), Page_size / sizeof(HIST_t)
@ -390,7 +401,7 @@ static void std_err (const char *str)
/* we'll use our own buffer so callers can still use fmtmk() and, yes the
leading tab is not the standard convention, but the standard is wrong
-- OUR msg won't get lost in screen clutter, like so many others! */
sprintf(buf, "\t%s: %s\n", Myname, str);
snprintf(buf, sizeof(buf), "\t%s: %s\n", Myname, str);
if (!Ttychanged) {
fprintf(stderr, buf);
exit(1);
@ -409,7 +420,8 @@ static void suspend (int dont_care_sig)
(void)dont_care_sig;
/* reset terminal */
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
printf("%s%s", tg2(0, Screen_rows), Cap_curs_norm);
putp(tg2(0, Screen_rows));
putp(Cap_curs_norm);
fflush(stdout);
raise(SIGSTOP);
/* later, after SIGCONT... */
@ -423,7 +435,7 @@ static void suspend (int dont_care_sig)
/*
* Make the appropriate caps/color strings and set some
* lengths which are used to distinguish twix the displayed
* columns and an actual printf row!
* columns and an actual printed row!
* note: we avoid the use of background color so as to maximize
* compatibility with the user's xterm settings */
static void capsmk (WIN_t *q)
@ -447,7 +459,7 @@ static void capsmk (WIN_t *q)
strcpy(Cap_home, tIF(cursor_home));
strcpy(Cap_norm, tIF(exit_attribute_mode));
strcpy(Cap_reverse, tIF(enter_reverse_mode));
sprintf(Caps_off, "%s%s", Cap_norm, tIF(orig_pair));
snprintf(Caps_off, sizeof(Caps_off), "%s%s", Cap_norm, tIF(orig_pair));
if (tgoto(cursor_address, 1, 1)) Cap_can_goto = 1;
capsdone = 1;
}
@ -456,13 +468,13 @@ static void capsmk (WIN_t *q)
the job's done until he/she/it has a change-of-heart */
if (CHKw(q, Show_COLORS) && max_colors > 0) {
strcpy(q->capclr_sum, tparm(set_a_foreground, q->summclr));
sprintf(q->capclr_msg, "%s%s"
snprintf(q->capclr_msg, sizeof(q->capclr_msg), "%s%s"
, tparm(set_a_foreground, q->msgsclr), Cap_reverse);
sprintf(q->capclr_pmt, "%s%s"
snprintf(q->capclr_pmt, sizeof(q->capclr_pmt), "%s%s"
, tparm(set_a_foreground, q->msgsclr), Cap_bold);
sprintf(q->capclr_hdr, "%s%s"
snprintf(q->capclr_hdr, sizeof(q->capclr_hdr), "%s%s"
, tparm(set_a_foreground, q->headclr), Cap_reverse);
sprintf(q->capclr_rownorm, "%s%s"
snprintf(q->capclr_rownorm, sizeof(q->capclr_rownorm), "%s%s"
, Caps_off, tparm(set_a_foreground, q->taskclr));
} else {
q->capclr_sum[0] = '\0';
@ -472,7 +484,7 @@ static void capsmk (WIN_t *q)
strcpy(q->capclr_rownorm, Cap_norm);
}
/* this guy's a composite, so we do him outside the if */
sprintf(q->capclr_rowhigh, "%s%s"
snprintf(q->capclr_rowhigh, sizeof(q->capclr_rowhigh), "%s%s"
, q->capclr_rownorm, CHKw(q, Show_HIBOLD) ? Cap_bold : Cap_reverse);
q->len_rownorm = strlen(q->capclr_rownorm);
q->len_rowhigh = strlen(q->capclr_rowhigh);
@ -496,7 +508,7 @@ static void msg_save (const char *fmts, ...)
vsnprintf(tmp, sizeof(tmp), fmts, va);
va_end(va);
/* we'll add some extra attention grabbers to whatever this is */
sprintf(Msg_delayed, "\a*** %s ***", strim(0, tmp));
snprintf(Msg_delayed, sizeof(Msg_delayed), "\a*** %s ***", strim(0, tmp));
Msg_awaiting = 1;
}
@ -505,7 +517,7 @@ static void msg_save (const char *fmts, ...)
* Show an error message (caller may include a '\a' for sound) */
static void show_msg (const char *str)
{
printf("%s%s %s %s%s"
PUTP("%s%s %s %s%s"
, tg2(0, Msg_row)
, Curwin->capclr_msg
, str
@ -521,7 +533,7 @@ static void show_msg (const char *str)
* Show an input prompt + larger cursor */
static void show_pmt (const char *str)
{
printf("%s%s%s: %s%s"
PUTP("%s%s%s: %s%s"
, tg2(0, Msg_row)
, Curwin->capclr_pmt
, str
@ -589,7 +601,7 @@ static void show_special (const char *glob)
case 5: case 6: case 7: case 8:
cap = Curwin->captab[(int)*sub_end];
*sub_end = '\0';
printf("%s%.*s%s", cap, room, sub_beg, Caps_off);
PUTP("%s%.*s%s", cap, room, sub_beg, Caps_off);
room -= (sub_end - sub_beg);
sub_beg = ++sub_end;
break;
@ -599,14 +611,15 @@ static void show_special (const char *glob)
if (0 >= room) break; /* skip substrings that won't fit */
} /* end: while 'subtrings' */
printf("%s\n", Cap_clr_eol); /* emulate truncated newline */
putp(Cap_clr_eol);
putp("\n"); /* emulate truncated newline */
glob = ++lin_end; /* point to next line (maybe) */
} /* end: while 'lines' */
/* if there's anything left in the glob (by virtue of no trailing '\n'),
it probably means caller wants to retain cursor position on this final
line -- ok then, we'll just do our 'fit-to-screen' thingy... */
if (*glob) printf("%.*s", Screen_cols, glob);
if (*glob) PUTP("%.*s", Screen_cols, glob);
fflush(stdout);
}
@ -623,7 +636,6 @@ static char *ask4str (const char *prompt)
memset(buf, '\0', sizeof(buf));
chin(1, buf, sizeof(buf) - 1);
putp(Cap_curs_norm);
return strim(0, buf);
}
@ -685,20 +697,18 @@ static const char *scale_num (unsigned num, const int width, const unsigned type
static char buf[TNYBUFSIZ];
float *dp;
char *up;
int n;
/* try an unscaled version first... */
if (-1 != (n = snprintf(buf, sizeof(buf), "%u", num))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), "%u", num)) return buf;
/* now try successively higher types until it fits */
for (up = nextup + type, dp = scale; *dp; ++dp, ++up) {
/* the most accurate version */
if (-1 != (n = snprintf(buf, sizeof(buf), "%.1f%c", num / *dp, *up))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), "%.1f%c", num / *dp, *up))
return buf;
/* the integer version */
if (-1 != (n = snprintf(buf, sizeof(buf), "%d%c", (int)(num / *dp), *up))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), "%d%c", (int)(num / *dp), *up))
return buf;
}
/* well shoot, this outta' fit... */
return "?";
@ -723,26 +733,25 @@ static const char *scale_tics (TICS_t tics, const int width)
#endif
static char buf[TNYBUFSIZ];
unsigned ss;
int n;
TICS_t t = (tics * 100) / (TICS_t)Hertz;
if (-1 != (n = snprintf(buf, sizeof(buf), T1
if (width >= snprintf(buf, sizeof(buf), T1
, (unsigned)t / 6000, (unsigned)(t / 100) % 60, (unsigned)t % 100))
&& width >= n) return buf;
return buf;
t /= 100;
ss = t % 60;
t /= 60;
if (-1 != (n = snprintf(buf, sizeof(buf), T2, (unsigned)t, ss))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), T2, (unsigned)t, ss))
return buf;
t /= 60;
if (-1 != (n = snprintf(buf, sizeof(buf), HH, (unsigned)t))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), HH, (unsigned)t))
return buf;
t /= 24;
if (-1 != (n = snprintf(buf, sizeof(buf), DD, (unsigned)t))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), DD, (unsigned)t))
return buf;
t /= 7;
if (-1 != (n = snprintf(buf, sizeof(buf), WW, (unsigned)t))
&& width >= n) return buf;
if (width >= snprintf(buf, sizeof(buf), WW, (unsigned)t))
return buf;
/* well shoot, this outta' fit... */
return "?";
@ -755,45 +764,6 @@ static const char *scale_tics (TICS_t tics, const int width)
}
static const char *format_interval_wide(unsigned long long tick64)
{
static char buf[TNYBUFSIZ];
unsigned day, hr, min, sec;
if( sizeof(long)==4 && (tick64>>32) ){ // if need 64-bit on 32-bit
sec = tick64 / Hertz; // seconds won't overflow 32-bit
min = sec/60u; // total minutes
}else{
unsigned long hz = Hertz;
unsigned long tick = tick64;
sec = tick / hz; // total seconds
min = sec/60u; // total minutes
if(min < 120u){ // less than 120 minutes --> use MMM:SS.XX
unsigned wee = tick - sec*hz;
if(100ul != hz){ // if jiffies aren't centiseconds
if(1000ul == hz) wee /= 10u;
else wee = wee * 100u / hz;
}
sec = sec - min * 60u; // seconds past minute
snprintf(buf, sizeof buf, "%3u:%02u.%02u", min, sec, wee);
return buf;
}
}
// won't fit in MMM:SS.XX format
sec = sec - min * 60u; // seconds past minute
hr = min / 60u; // total hours
min = min - hr * 60u; // min past the hour
if(hr < 48){
snprintf(buf, sizeof buf, "%3u:%02u:%02u", hr, min, sec);
return buf;
}
day = hr / 24u; // total days
hr = hr - day * 24u; // hours past the day
snprintf(buf, sizeof buf, "%3u-%02u:%02u", day, hr, min);
return buf;
}
/*
* Calculate and the elapsed time since the last update along with the
* scaling factor used in multiplication (vs. division) when calculating
@ -811,7 +781,7 @@ static void time_elapsed (void)
oldtimev.tv_sec = timev.tv_sec;
oldtimev.tv_usec = timev.tv_usec;
/* if in Solaris mode, adjust our scaling for all cpus */
Frame_scale = 100.0f / ((float)Hertz * (float)et * (Mode_irixps ? 1 : Cpu_tot));
Frame_tscale = 100.0f / ((float)Hertz * (float)et * (Mode_irixps ? 1 : Cpu_tot));
}
@ -844,7 +814,7 @@ static void *alloc_r (void *q, unsigned numb)
/*
* This guy's modeled on libproc's 'four_cpu_numbers' function except
* This guy's modeled on libproc's 'five_cpu_numbers' function except
* we preserve all cpu data in our CPUS_t array which is organized
* as follows:
* cpus[0] thru cpus[n] == tics for each separate cpu
@ -875,7 +845,7 @@ static CPUS_t *refreshcpus (CPUS_t *cpus)
, &cpus[Cpu_tot].u, &cpus[Cpu_tot].n, &cpus[Cpu_tot].s, &cpus[Cpu_tot].i, &cpus[Cpu_tot].w))
std_err("failed /proc/stat read");
/* and just in case we're 2.2.xx compiled without SMP support... */
memcpy(cpus, &cpus[1], sizeof(CPUS_t));
if (1 == Cpu_tot) memcpy(cpus, &cpus[1], sizeof(CPUS_t));
/* and now value each separate cpu's tics */
for (i = 0; 1 < Cpu_tot && i < Cpu_tot; i++) {
@ -896,17 +866,10 @@ static CPUS_t *refreshcpus (CPUS_t *cpus)
* This guy's modeled on libproc's 'readproctab' function except
* we reuse and extend any prior proc_t's. He's been customized
* for our specific needs and to avoid the use of <stdarg.h> */
static proc_t **refreshprocs (proc_t **tbl)
static proc_t **refreshprocs (proc_t **table, int flags)
{
#define PTRsz sizeof(proc_t *) /* eyeball candy */
#define ENTsz sizeof(proc_t)
static int flags = PROC_FILLMEM | PROC_FILLUSR
#ifdef UGH_ITS_4_RH
| PROC_FILLCMD
#else
| PROC_FILLGRP | PROC_FILLCOM
#endif
| PROC_FILLSTATUS | PROC_FILLSTAT;
static unsigned savmax = 0; /* first time, Bypass: (i) */
proc_t *ptsk = (proc_t *)-1; /* first time, Force: (ii) */
unsigned curmax = 0; /* every time (jeeze) */
@ -921,34 +884,34 @@ static proc_t **refreshprocs (proc_t **tbl)
/* i) Allocated Chunks: *Existing* table; refresh + reuse */
while (curmax < savmax) {
if (tbl[curmax]->cmdline) {
free(*tbl[curmax]->cmdline);
tbl[curmax]->cmdline = NULL;
if (table[curmax]->cmdline) {
free(*table[curmax]->cmdline);
table[curmax]->cmdline = NULL;
}
if (!(ptsk = readproc(PT, tbl[curmax]))) break;
if (!(ptsk = readproc(PT, table[curmax]))) break;
++curmax;
}
/* ii) Unallocated Chunks: *New* or *Existing* table; extend + fill */
while (ptsk) {
/* realloc as we go, keeping 'tbl' ahead of 'currmax++' */
tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
/* realloc as we go, keeping 'table' ahead of 'currmax++' */
table = alloc_r(table, (curmax + 1) * PTRsz);
/* here, readproc will allocate the underlying proc_t stg */
if ((ptsk = readproc(PT, NULL)))
tbl[curmax++] = ptsk;
table[curmax++] = ptsk;
}
closeproc(PT);
/* iii) Chunkless: make 'eot' entry, after possible extension */
if (curmax >= savmax) {
tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
table = alloc_r(table, (curmax + 1) * PTRsz);
/* here, we must allocate the underlying proc_t stg ourselves */
tbl[curmax] = alloc_c(ENTsz);
table[curmax] = alloc_c(ENTsz);
savmax = curmax + 1;
}
/* this frame's end, but not necessarily end of allocated space */
tbl[curmax]->pid = -1;
return tbl;
table[curmax]->pid = -1;
return table;
#undef PTRsz
#undef ENTsz
@ -981,6 +944,12 @@ static void before (char *me)
Cpu_map = alloc_r(NULL, sizeof(int) * Cpu_tot);
for (i = 0; i < Cpu_tot; i++)
Cpu_map[i] = i;
#ifndef PRETEND2_5_X
if ( 2 <= LINUX_VERSION_MAJOR(linux_version_code)
&& 5 <= LINUX_VERSION_MINOR(linux_version_code)
&& 41 <= LINUX_VERSION_PATCH(linux_version_code))
#endif
States_fmts = STATES_line2x5;
/* get virtual page size -- nearing huge! */
Page_size = getpagesize();
@ -1078,7 +1047,7 @@ static void parse_args (char **args)
. no deprecated/illegal use of 'breakargv:' with goto
. bunched args are actually handled properly and none are ignored
. we tolerate NO whitespace and NO switches -- maybe too tolerant? */
static const char *usage =
static const char usage[] =
" -hv | -bcisS -d delay -n iterations -p pid [,pid ...]";
float tmp_delay = MAXFLOAT;
char *p;
@ -1267,8 +1236,7 @@ static void display_fields (const char *fields, const char *xtra)
/* advance past any leading spaces */
for (p = Fieldstab[i].head; ' ' == *p; ++p)
;
printf("%s%s%c %c: %-10s = %s"
PUTP("%s%s%c %c: %-10s = %s"
, tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
, b ? Cap_bold : Cap_norm
, b ? '*' : ' '
@ -1280,7 +1248,7 @@ static void display_fields (const char *fields, const char *xtra)
putp(Curwin->capclr_rownorm);
while ((p = strchr(xtra, '\n'))) {
++i;
printf("%s%.*s"
PUTP("%s%.*s"
, tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
, (int)(p - xtra)
, xtra);
@ -1302,7 +1270,8 @@ static void fields_reorder (void)
char c, *p;
int i;
printf("%s%s", Cap_clr_scr, Cap_curs_huge);
putp(Cap_clr_scr);
putp(Cap_curs_huge);
display_fields(Curwin->fieldscur, FIELDS_xtra);
do {
show_special(fmtmk(FIELDS_current
@ -1335,7 +1304,8 @@ static void fields_sort (void)
strcpy(phoney, NUL_FIELDS);
x = i = Curwin->sortindx;
printf("%s%s", Cap_clr_scr, Cap_curs_huge);
putp(Cap_clr_scr);
putp(Cap_curs_huge);
do {
p = phoney + i;
*p = toupper(*p);
@ -1364,7 +1334,8 @@ static void fields_toggle (void)
char c, *p;
int i;
printf("%s%s", Cap_clr_scr, Cap_curs_huge);
putp(Cap_clr_scr);
putp(Cap_curs_huge);
do {
display_fields(Curwin->fieldscur, FIELDS_xtra);
show_special(fmtmk(FIELDS_current
@ -1418,7 +1389,8 @@ static void win_colsheads (WIN_t *q)
/* now we can build the true run-time columns header and format the
command column heading if P_CMD is really being displayed --
show_a_task is aware of the addition of winnum to the header */
sprintf(q->columnhdr, "%s", Mode_altscr ? fmtmk("%d", q->winnum) : "");
snprintf(q->columnhdr, sizeof(q->columnhdr), "%s"
, Mode_altscr ? fmtmk("%d", q->winnum) : "");
for (i = 0; i < q->maxpflgs; i++) {
h = Fieldstab[q->procflags[i]].head;
/* are we gonna' need the kernel symbol table? */
@ -1445,13 +1417,21 @@ static void win_colsheads (WIN_t *q)
}
/*
* Tell caller if a specific pflag is 'exposing itself' (whoa!) */
static inline int win_fldviz (WIN_t *q, PFLG_t flg)
{
PFLG_t *p = q->procflags + q->maxpflgs - 1;
while (*p != flg && q->procflags < p) --p;
return *p == flg;
}
/*
* Value a window's name and make the associated group name. */
static void win_names (WIN_t *q, const char *name)
{
/* these safeguards are totally unnecessary if our caller(s) are
internal, they can be trusted -- it's those darn users that we
worry 'bout... */
sprintf(q->winname, "%.*s", WINNAMSIZ -1, name);
sprintf(q->grpname, "%d:%.*s", q->winnum, WINNAMSIZ -1, name);
}
@ -1473,7 +1453,7 @@ static void win_select (char ch)
case 'a': /* we don't carry 'a' / 'w' in our */
Curwin = Curwin->next; /* pmt - they're here for a good */
break; /* friend of ours -- wins_colors. */
case 'w': /* (however, those lettrs work via */
case 'w': /* (however those letters work via */
Curwin = Curwin->prev; /* the pmt too but gee, end-loser */
break; /* should just press the darn key) */
case '1': case '2':
@ -1529,12 +1509,14 @@ static void wins_colors (void)
return;
}
winsclr(Curwin, 1);
printf("%s%s", Cap_clr_scr, Cap_curs_huge);
putp(Cap_clr_scr);
putp(Cap_curs_huge);
do {
putp(Cap_home);
/* this string is well above ISO C89's minimum requirements! */
show_special(fmtmk(COLOR_help
, Cap_home, procps_version, Curwin->grpname
, procps_version, Curwin->grpname
, CHKw(Curwin, Show_HIBOLD) ? "On" : "Off"
, CHKw(Curwin, Show_COLORS) ? "On" : "Off"
, tgt, clr, Curwin->winname));
@ -1752,7 +1734,7 @@ static void cpudo (CPUS_t *cpu, const char *pfx)
/* display some kinda' cpu state percentages
(who or what is explained by the passed prefix) */
show_special(fmtmk(STATES_line2
show_special(fmtmk(States_fmts
, pfx
, (float)u_frme * scale
, (float)s_frme * scale
@ -1791,7 +1773,6 @@ static void frame_states (proc_t **ppt, int show)
hist_new = hist_tmp;
total = running = sleeping = stopped = zombie = 0;
time_elapsed();
/* make a pass through the data to get stats */
@ -1817,8 +1798,8 @@ static void frame_states (proc_t **ppt, int show)
}
if (total+1 >= hist_siz) {
hist_siz = hist_siz * 5 / 4 + 100; // grow by at least 25%
hist_sav = alloc_r(hist_sav, sizeof(HIST_t)*hist_siz);
hist_new = alloc_r(hist_new, sizeof(HIST_t)*hist_siz);
hist_sav = alloc_r(hist_sav, sizeof(HIST_t) * hist_siz);
hist_new = alloc_r(hist_new, sizeof(HIST_t) * hist_siz);
}
/* calculate time in this process; the sum of user time (utime)
+ system time (stime) -- but PLEASE dont waste time and effort on
@ -1862,7 +1843,7 @@ static void frame_states (proc_t **ppt, int show)
char tmp[SMLBUFSIZ];
/* display each cpu's states separately */
for (i = 0; i < Cpu_tot; i++) {
sprintf(tmp, " Cpu%-2d:", Mode_irixps ? i : Cpu_map[i]);
snprintf(tmp, sizeof(tmp), " Cpu%-2d:", Mode_irixps ? i : Cpu_map[i]);
cpudo(&smpcpu[i], tmp);
}
}
@ -1935,7 +1916,7 @@ static void mkcol (WIN_t *q, PFLG_t idx, int sta, int *pad, char *buf, ...)
if (!CHKw(q, Show_HICOLS) || q->sortindx != idx) {
vsprintf(buf, Fieldstab[idx].fmts, va);
} else {
vsprintf(tmp, Fieldstab[idx].fmts, va);
vsnprintf(tmp, sizeof(tmp), Fieldstab[idx].fmts, va);
sprintf(buf, "%s%s", q->capclr_rowhigh, tmp);
*pad += q->len_rowhigh;
if (!CHKw(q, Show_HIROWS) || 'R' != sta) {
@ -1955,7 +1936,7 @@ static void show_a_task (WIN_t *q, proc_t *task)
far and away the most frequent and costly part of top's entire job! */
#define MKCOL(q,idx,sta,pad,buf,arg...) \
if (!b) \
sprintf(buf, f, ## arg); \
snprintf(buf, sizeof(buf), f, ## arg); \
else mkcol(q, idx, sta, pad, buf, ## arg);
char rbuf[ROWBUFSIZ];
int j, x, pad;
@ -2018,7 +1999,7 @@ static void show_a_task (WIN_t *q, proc_t *task)
#endif
break;
case P_CPU:
{ float u = (float)task->pcpu * Frame_scale;
{ float u = (float)task->pcpu * Frame_tscale;
if (99.9 < u) u = 99.9;
MKCOL(q, i, a, &pad, cbuf, u);
@ -2083,20 +2064,13 @@ static void show_a_task (WIN_t *q, proc_t *task)
, scale_num(PAGES_2K(task->size - task->resident), w, s));
break;
case P_TME:
{ TICS_t t;
t = task->utime + task->stime;
if (CHKw(q, Show_CTIMES))
t += (task->cutime + task->cstime);
MKCOL(q, i, a, &pad, cbuf, scale_tics(t, w));
}
case P_TM2:
{ TICS_t t;
t = task->utime + task->stime;
if (CHKw(q, Show_CTIMES))
t += (task->cutime + task->cstime);
MKCOL(q, i, a, &pad, cbuf, format_interval_wide(t));
MKCOL(q, i, a, &pad, cbuf, scale_tics(t, w));
}
break;
case P_TTY:
@ -2132,10 +2106,8 @@ static void show_a_task (WIN_t *q, proc_t *task)
strcat(rbuf, cbuf);
} /* end: for 'maxpflgs' */
/* This row buffer could be stuffed with parameterized strings.
We are thus advised to always use tputs/putp, but it works just
fine with good ol' printf... */
printf("\n%s%.*s%s%s", (CHKw(q, Show_HIROWS) && 'R' == task->state)
/* This row buffer could be stuffed with parameterized strings... */
PUTP("\n%s%.*s%s%s", (CHKw(q, Show_HIROWS) && 'R' == task->state)
? q->capclr_rowhigh : q->capclr_rownorm
, Screen_cols + pad
, rbuf
@ -2238,7 +2210,8 @@ static void do_key (unsigned c)
case '?':
{ char ch;
printf("%s%s", Cap_clr_scr, Cap_curs_huge);
putp(Cap_clr_scr);
putp(Cap_curs_huge);
/* this string is well above ISO C89's minimum requirements! */
show_special(fmtmk(KEYS_help
, procps_version
@ -2488,11 +2461,31 @@ static void do_key (unsigned c)
* and then, returning a pointer to the pointers to the proc_t's! */
static proc_t **do_summary (void)
{
#ifdef UGH_ITS_4_RH
#define myCMD PROC_FILLCMD
#define myGRP 0
#else
#define myCMD PROC_FILLCOM
#define myGRP PROC_FILLGRP
#endif
static proc_t **p_table = NULL;
int p_flags = PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS;
WIN_t *w;
/* first try to minimize the cost of this frame (cross your fingers) */
w = Curwin;
do {
if (!Mode_altscr || CHKw(w, VISIBLE_tsk)) {
p_flags |= (CHKw(w, Show_CMDLIN) && win_fldviz(w, P_CMD)) ? myCMD : 0;
p_flags |= win_fldviz(w, P_USR) ? PROC_FILLUSR : 0;
p_flags |= win_fldviz(w, P_GRP) ? myGRP : 0;
}
if (Mode_altscr) w = w->next;
} while (w != Curwin);
if (!p_table) {
/* whoa first time, gotta' prime the pump... */
p_table = refreshprocs(NULL);
p_table = refreshprocs(NULL, p_flags);
frame_states(p_table, 0);
putp(Cap_clr_scr);
sleep(1);
@ -2516,15 +2509,29 @@ static proc_t **do_summary (void)
/*
** Display Tasks and Cpu(s) states and also prime for potential 'pcpu',
** but NO table sort yet -- that's done on a per window basis! */
p_table = refreshprocs(p_table);
p_table = refreshprocs(p_table, p_flags);
frame_states(p_table, CHKw(Curwin, View_STATES));
/*
** Display Memory and Swap space usage */
frame_storage();
#ifndef YIELDCPU_OFF
/* jeeze pucker up, it's time to kiss the scheduler's butt...
Alright Mr. Kernel, that's ENOUGH already. This swell little program
is SICK and TIRED of being PUNISHED for its CAREFUL USE of cpu cycles
(quite unlike old top who just threw them away). You constantly make
me FIGHT my way back up the RUN-QUEUE! Dammit, I am GOOD, regardless
of whether your GOODNESS says so. So here's the deal: I'll yield the
darn cpu, if you'll promise to re-dispatch me real soon, ok? */
sched_yield();
#endif
SETw(Curwin, NEWFRAM_cwo);
return p_table;
#undef myCMD
#undef myGRP
}
@ -2543,7 +2550,7 @@ static void do_window (proc_t **ppt, WIN_t *q, int *lscr)
/*
** Display Column Headings -- and distract 'em while we sort (maybe) */
printf("\n%s%s%s%s", q->capclr_hdr, q->columnhdr, Caps_off, Cap_clr_eol);
PUTP("\n%s%s%s%s", q->capclr_hdr, q->columnhdr, Caps_off, Cap_clr_eol);
#ifdef SORT_SUPRESS
if (CHKw(Curwin, NEWFRAM_cwo)
@ -2597,7 +2604,6 @@ static void do_window (proc_t **ppt, WIN_t *q, int *lscr)
* -- i swear that's the whole truth, so-help-me ! */
static void sohelpme (int wix, int max)
{
WIN_t *w = Winstk[wix];
int i, rsvd, size, wins;
/* calc remaining number of visible windows + total 'user' lines */
@ -2621,12 +2627,8 @@ static void sohelpme (int wix, int max)
if (CHKw(Winstk[i], VISIBLE_tsk)) {
Winstk[i]->winlines =
Winstk[i]->maxtasks ? Winstk[i]->maxtasks : size;
w = Winstk[i];
}
}
/* award any remaining lines to the screen's last visible window
(for the best/most stable display) */
w->winlines += (max - wins) % wins;
}
@ -2682,7 +2684,7 @@ static void so_lets_see_em (void)
/* clear to end-of-screen (critical if last window is 'idleps off'),
then put the cursor in-its-place, and rid us of any prior frame's msg
(main loop must iterate such that we're always called before sleep) */
printf("%s%s%s", Cap_clr_eos, tg2(0, Msg_row), Cap_clr_eol);
PUTP("%s%s%s", Cap_clr_eos, tg2(0, Msg_row), Cap_clr_eol);
fflush(stdout);
}

38
top.h
View File

@ -34,8 +34,10 @@
/* Development/Debugging defines ----------------------------------- */
//#define ATEOJ_REPORT /* report a bunch of stuff, at end-of-job */
//#define PRETEND2_5_X /* pretend we're linux 2.5.x (for IO-wait) */
//#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */
//#define PRETENDNOCAP /* use a terminal without essential caps */
//#define YIELDCPU_OFF /* hang on tight, DON'T issue sched_yield */
/*###### Some Miscellaneous constants ##################################*/
@ -107,6 +109,15 @@
static int sort_ ## f (const proc_t **P, const proc_t **Q) { \
return Frame_srtflg * strcmp((*Q)->s, (*P)->s); }
/* Used to 'inline' those portions of the display requiring formatting
while ensuring we won't be blindsided by some whacko terminal's
'$<..>' (millesecond delay) lurking in a terminfo string. */
#define PUTP(fmt,arg...) do { \
char _str[ROWBUFSIZ]; \
snprintf(_str, sizeof(_str), fmt, ## arg); \
putp(_str); \
} while (0);
/*------ Special Macros (debug and/or informative) ---------------------*/
/* Orderly end, with any sort of message - see fmtmk */
@ -318,25 +329,21 @@ typedef struct win {
#define LOADAV_line "%s -%s\n"
#define LOADAV_line_alt "%s\06 -%s\n"
#define STATES_line1 "Tasks:\03" \
" %3u \02total,\03 %3u \02running,\03 %3u \02sleeping,\03" \
" %3u \02stopped,\03 %3u \02zombie\03\n"
#define STATES_line2 "%s\03" \
" %#5.1f%% \02user,\03 %#5.1f%% \02system,\03" \
" %#5.1f%% \02nice,\03 %#5.1f%% \02idle,\03 %#5.1f%% \02IO-wait\03\n"
" %3u \02total,\03 %3u \02running,\03 %3u \02sleeping,\03 %3u \02stopped,\03 %3u \02zombie\03\n"
#define STATES_line2x4 "%s\03" \
" %#5.1f%% \02user,\03 %#5.1f%% \02system,\03 %#5.1f%% \02nice,\03 %#5.1f%% \02idle\03\n"
#define STATES_line2x5 "%s\03" \
" %#5.1f%% \02user,\03 %#5.1f%% \02system,\03 %#5.1f%% \02nice,\03 %#5.1f%% \02idle,\03 %#5.1f%% \02IO-wait\03\n"
#ifdef CASEUP_SUMMK
#define MEMORY_line1 "Mem: \03" \
" %8uK \02total,\03 %8uK \02used,\03" \
" %8uK \02free,\03 %8uK \02buffers\03\n"
" %8uK \02total,\03 %8uK \02used,\03 %8uK \02free,\03 %8uK \02buffers\03\n"
#define MEMORY_line2 "Swap:\03" \
" %8uK \02total,\03 %8uK \02used,\03" \
" %8uK \02free,\03 %8uK \02cached\03\n"
" %8uK \02total,\03 %8uK \02used,\03 %8uK \02free,\03 %8uK \02cached\03\n"
#else
#define MEMORY_line1 "Mem: \03" \
" %8uk \02total,\03 %8uk \02used,\03" \
" %8uk \02free,\03 %8uk \02buffers\03\n"
" %8uk \02total,\03 %8uk \02used,\03 %8uk \02free,\03 %8uk \02buffers\03\n"
#define MEMORY_line2 "Swap:\03" \
" %8uk \02total,\03 %8uk \02used,\03" \
" %8uk \02free,\03 %8uk \02cached\03\n"
" %8uk \02total,\03 %8uk \02used,\03 %8uk \02free,\03 %8uk \02cached\03\n"
#endif
/* Keyboard Help specially formatted string(s) --
@ -435,7 +442,7 @@ typedef struct win {
/* Colors Help specially formatted string(s) --
see 'show_special' for syntax details + other cautions. */
#define COLOR_help \
"%sHelp for color mapping\02 - %s\n" \
"Help for color mapping\02 - %s\n" \
"current window: \01%s\06\n" \
"\n" \
" color -\03 04:25:44 up 8 days, 50 min, 7 users, load average:\n" \
@ -526,7 +533,7 @@ typedef struct win {
//atic void *alloc_c (unsigned numb);
//atic void *alloc_r (void *q, unsigned numb);
//atic CPUS_t *refreshcpus (CPUS_t *cpus);
//atic proc_t **refreshprocs (proc_t **tbl);
//atic proc_t **refreshprocs (proc_t **table, int flags);
/*------ Startup routines ----------------------------------------------*/
//atic void before (char *me);
//atic void configs_read (void);
@ -540,6 +547,7 @@ typedef struct win {
//atic void fields_toggle (void);
/*------ Windows/Field Groups support ----------------------------------*/
//atic void win_colsheads (WIN_t *q);
//atic inline int win_fldviz (WIN_t *q, int flg);
//atic void win_names (WIN_t *q, const char *name);
//atic void win_select (char ch);
//atic int win_warn (void);