top now has a forest view mode

This commit is contained in:
Craig Small 2011-08-30 22:05:45 +10:00
parent 0e6ac0db3e
commit 73ade5e2cb
3 changed files with 225 additions and 91 deletions

19
top.1
View File

@ -68,7 +68,7 @@
.ds SA summary area
.ds TA task area
.ds TD task display
.ds TT \fBtasks\fR or\fB threads\fR
.ds TT \fBprocesses\fR or \fBthreads\fR
.ds TW task window
\# Reference to the various widths/sizes ------------
\# - the max screen width limit
@ -461,6 +461,9 @@ fit in this field's current width.
That width depends upon other fields selected, their order and the current
screen width.
This field may also be impacted by the 'forest view' display mode.
\*(XC 'V' \*(CI for additional information regarding that mode.
\*(NT The 'COMMAND' field, unlike most columns, is not fixed-width.
When displayed, it plus any other variable width columns will be allocated
all remaining screen width (up to the maximum \*(WX characters).
@ -779,7 +782,7 @@ depending on the context in which they are issued.
l, t, 1, m
4c.\fI Task-Area-Commands \fR
Appearance: b, x, y, z
Content: c, f, F, S, u, U
Content: c, f, F, S, u, U, V
Size: #, i, n
Sorting: <, >, f, F, R
4d.\fI Color-Mapping \fR
@ -1063,6 +1066,18 @@ Different \*(TWs can can be used to filter different users.
Later, if you wish to monitor all tasks again in the \*(CW, re-issue this
command but just press <Enter> at the prompt.
.TP 7
\ \ \'\fBV\fR' :\fIForest-View-Mode \fR toggle \fR
In this mode, processes are reordered according to their parents and
the layout of the COMMAND column resembles that of a tree.
In forest view mode it is still possible to toggle between program
name and commamd line (\*(Xc 'c' \*(CI) or between processes and
threads (\*(Xc 'H' \*(CI).
\*(NT Typing any key affecting the sort order will exit forest view
mode in the \*(CW.
\*(XT 4c. TASK AREA Commands, SORTING for information on those keys.
.PP
.\" ..................................................
.B SIZE\fR of \*(TW

272
top.c
View File

@ -75,7 +75,7 @@ static unsigned Pg2K_shft = 0;
/* SMP, Irix/Solaris mode, Linux 2.5.xx support */
/* (assume no IO-wait stats, overridden if linux 2.5.41) */
static int Cpu_tot;
static float Cpu_pmax = 99.9; // for %CPU display (may later change!)
static float Cpu_pmax;
static const char *Cpu_States_fmts = STATES_line2x4;
/* Specific process id monitoring support */
@ -137,7 +137,7 @@ static int Cap_can_goto = 0;
The Stdout_buf is transparent to our code and regardless of whose
buffer is used, stdout is flushed at frame end or if interactive. */
static char *Pseudo_screen;
static int Pseudo_row;
static int Pseudo_row = -1;
static size_t Pseudo_size;
#ifndef OFF_STDIOLBF
// less than stdout's normal buffer but with luck mostly '\n' anyway
@ -162,6 +162,7 @@ static volatile int Frames_paused; // become a paused background job
// Frames_resize set by do_key() & sig_resize(), unset by calibrate_fields()
static volatile int Frames_resize; // time to rebuild all column headers
static int Frames_libflags; // PROC_FILLxxx flags
static int Frame_maxtask; // last known number of active tasks
// ie. current 'size' of proc table
static float Frame_etscale; // so we can '*' vs. '/' WHEN 'pcpu'
@ -332,7 +333,7 @@ static void bye_bye (const char *str) {
"\n\t Hertz = %u (%u bytes, %u-bit time)"
"\n\t Page_size = %d, Cpu_tot = %d"
"\n\t sizeof(CPU_t) = %u, sizeof(HST_t) = %u (%u HST_t's/Page), HHist_siz = %u"
"\n\t sizeof(proc_t) = %u, sizeof(proc_t.cmd) = %u, sizeof(proc_t *) = %u"
"\n\t sizeof(proc_t) = %u, sizeof(proc_t.cmd) = %u, sizeof(proc_t*) = %u"
"\n\t Frames_libflags = %08lX"
"\n\t SCREENMAX = %u, ROWMINSIZ = %u, ROWMAXSIZ = %u"
"\n\tTerminal: %s"
@ -364,7 +365,7 @@ static void bye_bye (const char *str) {
, (unsigned)Hertz, (unsigned)sizeof(Hertz), (unsigned)sizeof(Hertz) * 8
, Page_size, Cpu_tot
, (unsigned) sizeof(CPU_t), (unsigned)sizeof(HST_t), Page_size / (unsigned)sizeof(HST_t), HHist_siz
, (unsigned)sizeof(*p), (unsigned)sizeof(p->cmd), (unsigned)sizeof(p)
, (unsigned)sizeof(proc_t), (unsigned)sizeof(p->cmd), (unsigned)sizeof(proc_t*)
, (long)Frames_libflags
, (unsigned)SCREENMAX, (unsigned)ROWMINSIZ, (unsigned)ROWMAXSIZ
#ifdef PRETENDNOCAP
@ -1186,7 +1187,7 @@ static FLD_t Fieldstab[] = {
/* .head + .fmts anomolies:
entries shown with NULL are either valued at runtime (see zap_fieldstab)
or, in the case of .fmts, represent variable width fields
or, in the case of .fmts, may represent variable width fields
.lflg anomolies:
P_UED, L_NONE - natural outgrowth of 'stat()' in readproc (euid)
P_CPU, L_stat - never filled by libproc, but requires times (pcpu)
@ -1212,7 +1213,7 @@ static FLD_t Fieldstab[] = {
{ " NI ", "%3d ", -1, -1, SF(NCE), L_stat, "Nice Value" },
{ "nTH ", "%3d ", -1, -1, SF(THD), L_EITHER, "Number of Threads" },
{ NULL, NULL, -1, -1, SF(CPN), L_stat, "Last Used Cpu (SMP)" },
{ "%CPU ", NULL, -1, -1, SF(CPU), L_stat, "CPU Usage" },
{ " %CPU ", NULL, -1, -1, SF(CPU), L_stat, "CPU Usage" },
{ " TIME ", "%6.6s ", 6, -1, SF(TME), L_stat, "CPU Time" },
{ " TIME+ ", "%9.9s ", 9, -1, SF(TME), L_stat, "CPU Time, hundredths" },
{ "%MEM ", "%#4.1f ", -1, -1, SF(RES), L_statm, "Memory Usage (RES)" },
@ -1452,6 +1453,8 @@ static void calibrate_fields (void) {
if (Screen_cols > (int)strlen(w->columnhdr)) w->eolcap = Caps_endline;
else w->eolcap = Caps_off;
#endif
// to show only 'busy' processes requires L_stat...
if (!CHKw(w, Show_IDLEPS)) Frames_libflags |= L_stat;
// we must also accommodate an out of view sort field...
f = w->rc.sortindx;
Frames_libflags |= Fieldstab[f].lflg;
@ -1604,7 +1607,7 @@ static void fields_utility (void) {
if (!h) for (h = Fieldstab[f].head; ' ' == *h; ++h) ;
display_fields(i, (p != NULL));
putp(Cap_home);
show_special(1, fmtmk(FIELDS_heading, w->grpname, h));
show_special(1, fmtmk(FIELDS_heading, w->grpname, CHKw(w, Show_FOREST) ? "forest view" : h));
switch (key = keyin(0)) {
case kbd_UP:
@ -1633,7 +1636,11 @@ static void fields_utility (void) {
if (!p) { FLDtog(w, i); unSCRL }
break;
case 's':
if (!p) { w->rc.sortindx = f = FLDget(w, i); h = NULL; unSCRL }
#ifdef TREE_NORESET
if (!p && !CHKw(w, Show_FOREST)) { w->rc.sortindx = f = FLDget(w, i); h = NULL; unSCRL }
#else
if (!p) { w->rc.sortindx = f = FLDget(w, i); h = NULL; unSCRL; OFFw(w, Show_FOREST); }
#endif
break;
case 'a':
case 'w':
@ -1707,11 +1714,18 @@ always:
}
Cpu_pmax = 99.0;
Fieldstab[P_CPU].fmts = "%#4.1f ";
Fieldstab[P_CPU].fmts = " %#4.1f ";
if (Rc.mode_irixps && Cpu_tot > 1 && !Thread_mode) {
Cpu_pmax = 9999.0;
Fieldstab[P_CPU].fmts = "%4.0f ";
Cpu_pmax = 999.0;
Fieldstab[P_CPU].fmts = "%#5.1f ";
if (Cpu_tot > 10) {
Cpu_pmax = 99999.0;
Fieldstab[P_CPU].fmts = "%5.0f ";
}
}
// lastly, ensure we've got proper column headers...
calibrate_fields();
} // end: zap_fieldstab
/*###### Library Interface #############################################*/
@ -1733,7 +1747,6 @@ static CPU_t *cpus_refresh (CPU_t *cpus) {
if (sav_cpus != smp_num_cpus) {
Cpu_tot = sav_cpus = smp_num_cpus;
zap_fieldstab();
calibrate_fields();
if (fp) { fclose(fp); fp = NULL; }
if (cpus) { free(cpus); cpus = NULL; }
}
@ -1930,13 +1943,13 @@ static void prochlp (proc_t *this) {
* 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 **procs_refresh (proc_t **ppt) {
#define PTRsz sizeof(proc_t *)
#define ENTsz sizeof(proc_t)
static void procs_refresh (void) {
static proc_t **private_ppt; // our base proc_t pointer table
static unsigned savmax = 0; // first time, Bypass: (i)
proc_t *ptask = (proc_t *)-1; // first time, Force: (ii)
proc_t *ptask = (proc_t*)-1; // first time, Force: (ii)
unsigned curmax = 0; // every time (jeeze)
PROCTAB* PT;
int i;
proc_t*(*read_something)(PROCTAB*, proc_t*);
prochlp(NULL); // prep for a new frame
@ -1946,36 +1959,32 @@ static proc_t **procs_refresh (proc_t **ppt) {
// i) Allocated Chunks: *Existing* table; refresh + reuse
while (curmax < savmax) {
if (!(ptask = read_something(PT, ppt[curmax]))) break;
prochlp(ptask); // tally & complete this proc_t
if (!(ptask = read_something(PT, private_ppt[curmax]))) break;
prochlp(ptask); // tally & complete this proc_t
++curmax;
}
// ii) Unallocated Chunks: *New* or *Existing* table; extend + fill
while (ptask) {
// realloc as we go, keeping 'ppt' ahead of 'currmax++'
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
private_ppt = alloc_r(private_ppt, (curmax + 1) * sizeof(proc_t*));
// here, the library will allocate the underlying proc_t stg
if ((ptask = read_something(PT, NULL))) {
prochlp(ptask); // tally & complete this proc_t
ppt[curmax++] = ptask;
prochlp(ptask); // tally & complete this proc_t
private_ppt[curmax++] = ptask;
}
}
closeproc(PT);
// iii) Chunkless: make 'eot' entry, after ensuring proc_t exists
if (curmax >= savmax) {
ppt = alloc_r(ppt, (curmax + 1) * PTRsz);
// here, we must allocate the underlying proc_t stg ourselves
ppt[curmax] = alloc_c(ENTsz);
savmax = curmax + 1;
// iii) Chunkless: End frame, but not necessarily end of allocated space
if (savmax < curmax) savmax = curmax;
// lastly, refresh each window's proc pointers table...
for (i = 0; i < GROUPSMAX; i++) {
Winstk[i].ppt = alloc_r(Winstk[i].ppt, savmax * sizeof(proc_t*));
memcpy(Winstk[i].ppt, private_ppt, Frame_maxtask * sizeof(proc_t*));
}
// this frame's end, but not necessarily end of allocated space
ppt[curmax]->tid = -1;
return ppt;
#undef PTRsz
#undef ENTsz
} // end: procs_refresh
@ -2042,9 +2051,6 @@ static void before (char *me) {
memcpy(HHash_one, HHash_nul, sizeof(HHash_nul));
memcpy(HHash_two, HHash_nul, sizeof(HHash_nul));
#endif
// lastly, fill in the missing Fieldstab .head and .fmts members
zap_fieldstab();
} // end: before
@ -2128,8 +2134,8 @@ static void configs_read (void) {
goto just_default_em;
#endif
}
fscanf(fp, "\twinflags=%d, sortindx=%u, maxtasks=%d\n"
, &Winstk[i].rc.winflags, &Winstk[i].rc.sortindx, &Winstk[i].rc.maxtasks);
fscanf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d\n"
, &Winstk[i].rc.winflags, (int*)&Winstk[i].rc.sortindx, &Winstk[i].rc.maxtasks);
fscanf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d\n"
, &Winstk[i].rc.summclr, &Winstk[i].rc.msgsclr
, &Winstk[i].rc.headclr, &Winstk[i].rc.taskclr);
@ -2585,8 +2591,9 @@ static void wins_stage_2 (void) {
}
if (Batch)
OFFw(Curwin, View_SCROLL);
// this guy will build each window's columnhdr
calibrate_fields();
// fill in missing Fieldstab members and build each window's columnhdr
zap_fieldstab();
} // end: wins_stage_2
/*###### Interactive Input support (do_key helpers) ####################*/
@ -2612,7 +2619,7 @@ static void file_writerc (void) {
fprintf(fp, "%s\tfieldscur=%s\n"
, Winstk[i].rc.winname, Winstk[i].rc.fieldscur);
fprintf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d\n"
, Winstk[i].rc.winflags, Winstk[i].rc.sortindx
, Winstk[i].rc.winflags, (int)Winstk[i].rc.sortindx
, Winstk[i].rc.maxtasks);
fprintf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d\n"
, Winstk[i].rc.summclr, Winstk[i].rc.msgsclr
@ -2686,14 +2693,13 @@ static void keys_global (int ch) {
break;
case 'H':
Thread_mode = !Thread_mode;
show_msg(fmtmk("Show threads %s", Thread_mode ? "On" : "Off"));
zap_fieldstab();
if (!CHKw(w, View_STATES))
show_msg(fmtmk("Show threads %s", Thread_mode ? "On" : "Off"));
break;
case 'I':
if (Cpu_tot > 1) {
Rc.mode_irixps = !Rc.mode_irixps;
show_msg(fmtmk("Irix mode %s", Rc.mode_irixps ? "On" : "Off"));
zap_fieldstab();
} else
show_msg(err_notsmp);
break;
@ -2770,6 +2776,9 @@ static void keys_task (int ch) {
}
break;
case '<':
#ifdef TREE_NORESET
if (CHKw(w, Show_FOREST)) break;
#endif
if (VIZCHKw(w)) {
FLG_t *p = w->procflgs + w->maxpflgs - 1;
while (p > w->procflgs && *p != w->rc.sortindx) --p;
@ -2778,11 +2787,19 @@ static void keys_task (int ch) {
#ifndef USE_X_COLHDR
if (P_MAXPFLGS < *p) --p;
#endif
if (p >= w->procflgs) w->rc.sortindx = *p;
if (p >= w->procflgs) {
w->rc.sortindx = *p;
#ifndef TREE_NORESET
OFFw(w, Show_FOREST);
#endif
}
}
}
break;
case '>':
#ifdef TREE_NORESET
if (CHKw(w, Show_FOREST)) break;
#endif
if (VIZCHKw(w)) {
FLG_t *p = w->procflgs + w->maxpflgs - 1;
while (p > w->procflgs && *p != w->rc.sortindx) --p;
@ -2791,7 +2808,12 @@ static void keys_task (int ch) {
#ifndef USE_X_COLHDR
if (P_MAXPFLGS < *p) ++p;
#endif
if (p < w->procflgs + w->maxpflgs) w->rc.sortindx = *p;
if (p < w->procflgs + w->maxpflgs) {
w->rc.sortindx = *p;
#ifndef TREE_NORESET
OFFw(w, Show_FOREST);
#endif
}
}
}
break;
@ -2816,7 +2838,14 @@ static void keys_task (int ch) {
VIZTOGw(w, Show_IDLEPS);
break;
case 'R':
VIZTOGw(w, Qsrt_NORMAL);
#ifdef TREE_NORESET
if (!CHKw(w, Show_FOREST)) VIZTOGw(w, Qsrt_NORMAL);
#else
if (VIZCHKw(w)) {
TOGw(w, Qsrt_NORMAL);
OFFw(w, Show_FOREST);
}
#endif
break;
case 'S':
if (VIZCHKw(w)) {
@ -2832,6 +2861,13 @@ static void keys_task (int ch) {
show_msg(errmsg);
}
break;
case 'V':
if (VIZCHKw(w)) {
TOGw(w, Show_FOREST);
if (!ENUviz(w, P_CMD))
show_msg(fmtmk("Forest mode %s", CHKw(w, Show_FOREST) ? "On" : "Off"));
}
break;
case 'x':
if (VIZCHKw(w)) {
TOGw(w, Show_HICOLS);
@ -2949,6 +2985,11 @@ static void keys_xtra (int ch) {
// const char *xmsg;
WIN_t *w = Curwin; // avoid gcc bloat with a local copy
#ifdef TREE_NORESET
if (CHKw(w, Show_FOREST)) return;
#else
OFFw(w, Show_FOREST);
#endif
/* these keys represent old-top compatability --
they're grouped here so that if users could ever be weaned,
we would just whack do_key's key_tab entry and this function... */
@ -2976,6 +3017,67 @@ static void keys_xtra (int ch) {
// show_msg(fmtmk("%s sort compatibility key honored", xtab[i].xmsg));
} // end: keys_xtra
/*###### Forest View support ###########################################*/
/*
* We try to keep most existing code unaware of our activities. */
static proc_t **Seed_ppt; // temporary window ppt ptr
static proc_t **Tree_ppt; // resized by forest_create
static int Tree_idx; // frame_make initializes
/*
* This little recursive guy is the real forest view workhorse.
* He fills in the Tree_ppt array and also sets the child indent
* level which is stored in an unused proc_t padding byte. */
static void forest_add (const int self, const int level) {
int i;
Tree_ppt[Tree_idx] = Seed_ppt[self]; // add this as root or child
Tree_ppt[Tree_idx++]->pad_3 = level; // borrow 1 byte, 127 levels
for (i = self + 1; i < Frame_maxtask; i++) {
if (Seed_ppt[self]->tid == Seed_ppt[i]->tgid
|| (Seed_ppt[self]->tid == Seed_ppt[i]->ppid && Seed_ppt[i]->tid == Seed_ppt[i]->tgid))
forest_add(i, level + 1); // got one child any others?
}
} // end: forest_add
/*
* This routine is responsible for preparing the proc_t's for
* a forest display in the designated window. Upon completion,
* he'll replace the original window ppt with our specially
* ordered forest version. */
static void forest_create (WIN_t *q) {
static int hwmsav;
Seed_ppt = q->ppt; // avoid passing WIN_t ptrs
if (!Tree_idx) { // do just once per frame
int i = 0;
Frame_srtflg = -1; // put in ascending ppid order
qsort(Seed_ppt, Frame_maxtask, sizeof(proc_t*), Fieldstab[P_PPD].sort);
if (hwmsav < Frame_maxtask) { // grow, but never shrink
hwmsav = Frame_maxtask;
Tree_ppt = alloc_r(Tree_ppt, sizeof(proc_t*) * hwmsav);
}
while (0 == Seed_ppt[i]->ppid) // identify trees (expect 2)
forest_add(i++, 0); // add parent plus children
}
memcpy(Seed_ppt, Tree_ppt, sizeof(proc_t*) * Frame_maxtask);
} // end: forest_create
/*
* This guy adds the artwork to either p->cmd or p->cmdline
* when in forest view mode, otherwise he just returns 'em. */
static inline const char *forest_display (const WIN_t *q, const proc_t *p) {
static char buf[ROWMINSIZ];
const char *which = (CHKw(q, Show_CMDLIN)) ? *p->cmdline : p->cmd;
if (!CHKw(q, Show_FOREST) || !p->pad_3) return which;
snprintf(buf, sizeof(buf), "%*s%s", 4 * p->pad_3, " `- ", which);
return buf;
} // end: forest_display
/*###### Main Screen routines ##########################################*/
/*
@ -2991,7 +3093,7 @@ static void do_key (int ch) {
{ '1', 'C', 'l', 'm', 't' } },
{ keys_task,
{ '#', '<', '>', 'b', 'c', 'i', 'n', 'R', 'S'
, 'U', 'u', 'x', 'y', 'z' } },
, 'U', 'u', 'V', 'x', 'y', 'z' } },
{ keys_window,
{ '+', '-', '=', '_', 'A', 'a', 'G', 'w'
, kbd_UP, kbd_DOWN, kbd_LEFT, kbd_RIGHT, kbd_PGUP, kbd_PGDN
@ -3038,7 +3140,9 @@ static void do_key (int ch) {
'c' - likely when !Mode_altscr, maybe when Mode_altscr
'F' - likely
'f' - likely
'G' - likely
'g' - likely
'H' - likely (%CPU .fmts)
'I' - likely (%CPU .fmts)
'Z' - likely, if 'Curwin' changed when !Mode_altscr
'-' - likely (restricted to Mode_altscr)
'_' - likely (restricted to Mode_altscr)
@ -3108,24 +3212,12 @@ static void summaryhlp (CPU_t *cpu, const char *pfx) {
* 3) Displaying task/cpu states (maybe)
* 4) Displaying memory & swap usage (maybe)
* and then, returning a pointer to the pointers to the proc_t's! */
static proc_t **summary_show (void) {
static void summary_show (void) {
#define isROOM(f,n) (CHKw(w, f) && Msg_row + (n) < Screen_rows - 1)
#define anyFLG 0xffffff
static proc_t **p_table = NULL;
static CPU_t *smpcpu = NULL;
WIN_t *w = Curwin; // avoid gcc bloat with a local copy
// whoa first time, gotta' prime the pump...
if (!p_table) {
p_table = procs_refresh(NULL);
putp(Cap_clr_scr);
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)) {
if (!Rc.mode_altscr)
@ -3182,7 +3274,6 @@ static proc_t **summary_show (void) {
#undef mkS
}
return p_table;
#undef isROOM
#undef anyFLG
} // end: summary_show
@ -3224,8 +3315,7 @@ static void task_show (const WIN_t *q, const proc_t *p) {
makeVAR(p->cgroup ? *p->cgroup : "n/a");
break;
case P_CMD:
if (CHKw(q, Show_CMDLIN)) makeVAR(*p->cmdline)
else makeVAR(p->cmd);
makeVAR(forest_display(q, p));
break;
case P_COD:
makeCOL(scale_num(pages2K(p->trs), w, s));
@ -3390,7 +3480,7 @@ static void task_show (const WIN_t *q, const proc_t *p) {
/*
* Squeeze as many tasks as we can into a single window,
* after sorting the passed proc table. */
static int window_show (proc_t **ppt, WIN_t *q, int wmax) {
static int window_show (WIN_t *q, int wmax) {
/* the isBUSY macro determines if a task is 'active' --
it returns true if some cpu was used since the last sample.
( actual 'running' tasks will be a subset of those selected ) */
@ -3401,29 +3491,33 @@ static int window_show (proc_t **ppt, WIN_t *q, int wmax) {
// Display Column Headings -- and distract 'em while we sort (maybe)
PUFF("\n%s%s%s", q->capclr_hdr, q->columnhdr, q->eolcap);
if (CHKw(q, Qsrt_NORMAL)) Frame_srtflg = 1; // this one's always needed!
else Frame_srtflg = -1;
Frame_ctimes = CHKw(q, Show_CTIMES); // this and next, only maybe
Frame_cmdlin = CHKw(q, Show_CMDLIN);
qsort(ppt, Frame_maxtask, sizeof(proc_t *), Fieldstab[q->rc.sortindx].sort);
if (CHKw(q, Show_FOREST))
forest_create(q);
else {
if (CHKw(q, Qsrt_NORMAL)) Frame_srtflg = 1; // this is always needed!
else Frame_srtflg = -1;
Frame_ctimes = CHKw(q, Show_CTIMES); // this & next, only maybe
Frame_cmdlin = CHKw(q, Show_CMDLIN);
qsort(q->ppt, Frame_maxtask, sizeof(proc_t*), Fieldstab[q->rc.sortindx].sort);
}
i = q->begtask;
if (i >= Frame_maxtask) i = q->begtask = Frame_maxtask - 1;
lwin = 1; // 1 for the ol' column header
wmax = winMIN(wmax, q->winlines+1); // ditto for winlines, too
lwin = 1; // 1 for the column header
wmax = winMIN(wmax, q->winlines + 1); // ditto for winlines, too
/* the least likely scenario is also the most costly, so we'll try to avoid
checking some stuff with each iteration and check it just once... */
if (CHKw(q, Show_IDLEPS) && !q->usrseltyp)
while (-1 != ppt[i]->tid && lwin < wmax) {
task_show(q, ppt[i++]);
while (i < Frame_maxtask && lwin < wmax) {
task_show(q, q->ppt[i++]);
++lwin;
}
else
while (-1 != ppt[i]->tid && lwin < wmax) {
if ((CHKw(q, Show_IDLEPS) || isBUSY(ppt[i]))
&& user_matched(q, ppt[i])) {
task_show(q, ppt[i]);
while (i < Frame_maxtask && lwin < wmax) {
if ((CHKw(q, Show_IDLEPS) || isBUSY(q->ppt[i]))
&& user_matched(q, q->ppt[i])) {
task_show(q, q->ppt[i]);
++lwin;
}
++i;
@ -3482,29 +3576,39 @@ static void framehlp (int wix, int max) {
*/
static void frame_make (void) {
WIN_t *w = Curwin; // avoid gcc bloat with a local copy
proc_t **ppt;
int i, scrlins;
// deal with potential signals since the last time around...
if (Frames_endpgm) bye_bye(NULL);
if (Frames_paused) pause_pgm();
if (Frames_resize) calibrate_fields();
if (Frames_resize) zap_fieldstab();
// whoa first time, gotta' prime the pump...
if (-1 == Pseudo_row) {
procs_refresh();
putp(Cap_clr_scr);
usleep(LIB_USLEEP);
} else
putp(Batch ? "\n\n" : Cap_home);
putp(Cap_curs_hide);
Pseudo_row = Msg_row = scrlins = 0;
ppt = summary_show();
procs_refresh();
sysinfo_refresh(0);
Tree_idx = Pseudo_row = Msg_row = scrlins = 0;
summary_show();
Max_lines = (Screen_rows - Msg_row) - 1;
if (!Rc.mode_altscr) {
// only 1 window to show so, piece o' cake
w->winlines = w->rc.maxtasks ? w->rc.maxtasks : Max_lines;
scrlins = window_show(ppt, w, Max_lines);
scrlins = window_show(w, Max_lines);
} else {
// maybe NO window is visible but assume, pieces o' cakes
for (i = 0 ; i < GROUPSMAX; i++) {
if (CHKw(&Winstk[i], Show_TASKON)) {
framehlp(i, Max_lines - scrlins);
scrlins += window_show(ppt, &Winstk[i], Max_lines - scrlins);
scrlins += window_show(&Winstk[i], Max_lines - scrlins);
}
if (Max_lines <= scrlins) break;
}

25
top.h
View File

@ -35,6 +35,7 @@
//#define RMAN_IGNORED /* don't consider auto right margin glitch */
//#define STRCMPNOCASE /* use strcasecmp vs. strcmp when sorting */
//#define TERMIOS_ONLY /* just limp along with native input only */
//#define TREE_NORESET /* sort keys do NOT force forest view OFF */
//#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */
@ -149,7 +150,7 @@ enum scale_num {
};
/* This typedef just ensures consistent 'process flags' handling */
typedef unsigned FLG_t;
typedef unsigned char FLG_t;
/* These typedefs attempt to ensure consistent 'ticks' handling */
typedef unsigned long long TIC_t;
@ -233,6 +234,7 @@ typedef struct CPU_t {
#define Show_CTIMES 0x000040 // 'S' - show times as cumulative
#define Show_IDLEPS 0x000020 // 'i' - show idle processes (all tasks)
#define Show_TASKON 0x000010 // '-' - tasks showable when Mode_altscr
#define Show_FOREST 0x000002 // 'V' - show cmd/cmdlines with ascii art
#define Qsrt_NORMAL 0x000004 // 'R' - reversed column sort (high to low)
// these flag(s) have no command as such - they're for internal use
#define EQUWINS_xxx 0x000001 // rebalance all wins & tasks (off 'i'/ 'n')
@ -307,6 +309,7 @@ typedef struct WIN_t {
#endif
*eolcap, // window specific eol termcap
*captab [CAPTABMAX]; // captab needed by show_special()
proc_t **ppt; // this window's proc_t ptr array
struct WIN_t *next, // next window in window stack
*prev; // prior window in window stack
} WIN_t;
@ -325,6 +328,14 @@ typedef struct WIN_t {
#define FLDget(q,i) ((FLG_t)((q)->rc.fieldscur[i] & 0x7f) - FLD_OFFSET)
#define FLDtog(q,i) ((q)->rc.fieldscur[i] ^= 0x80)
#define FLDviz(q,i) ((q)->rc.fieldscur[i] & 0x80)
#define ENUchk(w,E) (NULL != strchr((w)->rc.fieldscur, (E + FLD_OFFSET) | 0x80))
#define ENUset(w,E) do { char *t; \
if ((t = strchr((w)->rc.fieldscur, E + FLD_OFFSET))) \
*t = (E + FLD_OFFSET) | 0x80; \
/* else fieldscur char already has high bit on! */ \
} while (0)
#define ENUviz(w,E) (NULL != memchr((w)->procflgs, E, (w)->maxpflgs))
/* Special Section: end ------------------------------------------ */
/* /////////////////////////////////////////////////////////////// */
@ -495,7 +506,7 @@ typedef struct WIN_t {
" f,F Manage Fields: add/remove; change order; select sort field\n" \
"\n" \
" <,> . Move sort field: '\01<\02' next col left; '\01>\02' next col right\n" \
" R,H . Toggle: '\01R\02' normal/reverse sort; '\01H\02' show threads\n" \
" R,H,V . Toggle: '\01R\02' norm/rev sort; '\01H\02' show threads; '\01V\02' forest view\n" \
" c,i,S . Toggle: '\01c\02' cmd name/line; '\01i\02' idle tasks; '\01S\02' cumulative time\n" \
" x\05,\01y\05 . Toggle highlights: '\01x\02' sort field; '\01y\02' running tasks\n" \
" z\05,\01b\05 . Toggle: '\01z\02' color/mono; '\01b\02' bold/reverse (only if 'x' or 'y')\n" \
@ -649,7 +660,7 @@ typedef struct WIN_t {
//atic inline void hstput (unsigned idx);
#endif
//atic void prochlp (proc_t *p);
//atic proc_t **procs_refresh (proc_t **ppt);
//atic void procs_refresh (void);
//atic void sysinfo_refresh (int forced);
/*------ Startup routines ----------------------------------------------*/
//atic void before (char *me);
@ -673,12 +684,16 @@ typedef struct WIN_t {
//atic void keys_task (int ch);
//atic void keys_window (int ch);
//atic void keys_xtra (int ch);
/*------ Forest View support -------------------------------------------*/
//atic void forest_add (const int self, const int level);
//atic void forest_create (WIN_t *q);
//atic inline const char *forest_display (const WIN_t *q, const proc_t *p);
/*------ Main Screen routines ------------------------------------------*/
//atic void do_key (int ch);
//atic void summaryhlp (CPU_t *cpu, const char *pfx);
//atic proc_t **summary_show (void);
//atic void summary_show (void);
//atic void task_show (const WIN_t *q, const proc_t *p);
//atic int window_show (proc_t **ppt, WIN_t *q, int wmax);
//atic int window_show (WIN_t *q, int wmax);
/*------ Entry point plus two ------------------------------------------*/
//atic void framehlp (int wix, int max);
//atic void frame_make (void);