diff --git a/top.1 b/top.1 index 34c0865b..3ab9e28d 100644 --- a/top.1 +++ b/top.1 @@ -23,7 +23,7 @@ . .\" Setup //////////////////////////////////////////////////////////////// \# ** Comment out '.nr' or set to 0 to eliminate WIDTH fiddlin' ! -.nr half_xtra 4 +.nr half_xtra 0 . . ll +(\n[half_xtra] + \n[half_xtra]) . @@ -79,7 +79,7 @@ \# - hey, these two ain't too shabby, either . ds Us this\ \*(Me . ds US \fBthis\fR\ \*(Me -\# - other misc strings for consistent usage +\# - other misc strings for consistent usage/emphasis . ds F \fIOff\fR . ds O \fIOn\fR . @@ -108,7 +108,7 @@ . .\" ////////////////////////////////////////////////////////////////////// .\" ---------------------------------------------------------------------- -.TH TOP 1 "June 2002" "Linux" "Linux User's Manual" +.TH TOP 1 "September 2002" "Linux" "Linux User's Manual" .\" ---------------------------------------------------------------------- @@ -124,7 +124,7 @@ top \- display Linux tasks \*(ME \-\fBhv\fR | \-\fBbcisS\fR \-\fBd\fI delay\fR \-\fBn\fI iterations\fR \-\fBp\fI pid\fR [,\fI pid\fR ...] -The traditional switches '-' and even whitespace are optional. +The traditional switches '-' and whitespace are optional. .\" ---------------------------------------------------------------------- @@ -158,16 +158,16 @@ Details regarding their exploitation will be covered in later sections. .\" ...................................................................... .SS Expanded Configurable Display Support .New -In an SMP environment, you can choose between a\fB summary\fR display or -you may show\fB each \*(Pu\fR separately. -This could be an important provision for a massively-parallel machine, where -screen height is insufficient to simultaneously accommodate all \*(Pu -states plus a meaningful \*(TD. +In an SMP environment, screen height may be insufficient to simultaneously +accommodate all \*(Pu states plus a meaningful \*(TD. +So with \*(Us, you can alternate between a\fB summary\fR display or one +showing\fB each \*(Pu\fR separately. +No longer must this choice be irrevocably made at startup. .New -There are new fields. -With \*(Us,\fB any\fR field is selectable for sorting and your sorted -column can be\fB instantly reversed\fR. +There are new fields and with \*(Us,\fB any\fR field is selectable for sorting. +Plus, your sorted column can be\fB instantly reversed\fR with just a +single keystroke. .New You may optionally apply 2 distinct types of\fB highlighting\fR to @@ -358,7 +358,7 @@ command line\fR \*(EM a subject soon to be dealt with. * 'c' - Command line \fBOff\fR (name, not cmdline) * 'i' - Idle tasks On\ \ (show all tasks) 'R' - Reverse sort On\ \ (sort pids high-to-low) - * 'S' - Cumulative time \fBOff\fR (exclude dead child) + * 'S' - Cumulative time \fBOff\fR (exclude dead children) 'x' - Column hilite \fBOff\fR\ (no, sort field) 'y' - Row hilite On\ \ (yes, running tasks) 'z' - color/mono \fBOff\fR\ (no, colors) @@ -392,8 +392,8 @@ Remaining Table of Contents b. SELECTING and ORDERING Columns 3.\fB INTERACTIVE Commands\fR a. GLOBAL Commands - b. SUMMARY Display Commands - c. TASK Display Commands + b. SUMMARY Area Commands + c. TASK Area Commands d. COLOR Mapping 4.\fB ALTERNATE\-DISPLAY Mode\fR a. WINDOWS Overview @@ -410,8 +410,10 @@ Remaining Table of Contents b. Bouncing Windows c. The Big Bird Window 7.\fB NOTES and Rantings\fR - a. The top BINARY - b. The top SOURCES + a. The top Binary + b. Comparing Performance + c. Cost of Stuff + d. The top Sources -*- Rant On, and on -*- lastly,\fB the usual\fR... 8. BUGS, 9. HISTORY Former top, 10. AUTHOR, 11. SEE ALSO @@ -432,7 +434,7 @@ optional. Starts \*(Me in 'Batch mode', which could be useful for sending output from \*(Me to other programs or to a file. In this mode, \*(Me will\fB not\fR accept input and runs until the iterations -limit you've set with the 'n' option or until killed. +limit you've set with the '-n' \*(CO or until killed. Output is plain text suitable for any dumb terminal. .br @@ -516,7 +518,7 @@ In fact, one could argue that this switch has little practical use\fB except\fR to test the nifty\fI delayed message handling\fR \*(Us employs during bootstrap. Oh, you wanna' see? -Test thus:\ \ top\fB d.1s\fR +Test thus:\ \ \*(Me\fB d.1s\fR .Rjb 3 ( see, NO '-' & 'sp' but ) ( you\fB can't change delay\fR ) @@ -524,14 +526,14 @@ Test thus:\ \ top\fB d.1s\fR .Rje Don't bother trying that precise command line with your old top -\*(EM he'll completely overlook that 's' option because +\*(EM he'll completely overlook that 's' \*(CO because he-sees-poorly-but-won't-wear-glasses. .TP 5 \-\fBS\fR :\fB Cumulative time mode\fR toggle Starts \*(Me with the last remembered '\fBS\fR' state reversed. When 'Cumulative mode' is \*O, each process is listed with the \*(Pu -time that it\fB and\fR its dead children has used. +time that it\fB and\fR its dead children have used. \*(XC 'S' \*(CI for additional information regarding this mode. .TP 5 @@ -547,11 +549,12 @@ Show library version and the usage prompt, then quit. .\" ---------------------------------------------------------------------- Listed below are \*(Us's\fB available\fR fields. They are always associated with the letter shown, regardless of the position -you may have established for them with the 'o' (Order fields) \*(CI. +you may have established for them with the 'o' (Order fields) \*(CI, reviewed +in the following topic. Any field is selectable as the\fB sort field\fR, and you control whether they are sorted high-to-low or low-to-high. -For additional information on sort provisions \*(Xt 3c. TASK Display Commands. +For additional information on sort provisions \*(Xt 3c. TASK Area Commands. .TP 3 a:\fB PID\fR \*(EM Process Id\fR @@ -564,7 +567,8 @@ The process ID of a task's parent. .TP 3 c:\fB PGID\fR \*(EM Process Group Id\fR -The group to which a task belongs which in turn is part of job control. +The grouping of tasks which becomes part of job control. +It is used for distribution of signals and to arbitrate terminal I/O requests. There is one process group per pipeline. .TP 3 @@ -723,12 +727,11 @@ to provide for the potential growth of program names into command lines! .TP 3 y:\fB WCHAN\fR \*(EM Sleeping in Function -Depending on the availability of\fI /boot/System.map\fR (the kernel link map) -or\fI /boot/psdatabase\fR, this field will show the \fB name\fR or -the\fB address\fR of the kernel function in which the task is -currently sleeping. -Running tasks will display a dash '-' in this column (but only if you're using -the best, the most proper libproc). +Depending on the availability of the kernel link map ('System.map'), +this field will show the \fB name\fR or the\fB address\fR of the kernel +function in which the task is currently sleeping. +Running tasks will display a dash ('-') in this column (but only if you're +using the best, the most proper libproc). .in +4 \*(NT By displaying this field, \*(Me's own working set will be increased by @@ -740,7 +743,7 @@ Your only means of reducing that overhead will be to stop and restart \*(Me. z:\fB Flags\fR \*(EM Task Flags This column represents the task's current scheduling flags which \*(Us expresses in hexadecimal notation, but with zeros suppressed. -These flags are officially documented in . +These flags are officially documented in . Less formal documentation can also be found on the 'Fields select' and 'Order fields' screens \*(EM the next topic. @@ -933,7 +936,7 @@ These commands always impact just the \*(CW/field group. .TP 7 \ \ \'\fBl\fR\' :\fIToggle_Load_Average/Uptime\fR \*(EM On/Off -This is the line containing the program name (possibly an alias) when +This is also the line containing the program name (possibly an alias) when operating in \*(FM or the \*(CW name when operating in \*(AM. If you murder-this-line, \*(Me will prosecute you. @@ -992,16 +995,15 @@ Further, it will only be available when at least one of those toggles is \*O. You probably don't need a constant visual reminder of your chosen sort field and \*(Us hopes that you always run with 'column highlight' \*F, due to the cost in path-length. -However, if you forget which field \*(Me is sorting it can serve as a -quick visual reminder. +However, if you forget which field \*(Me is sorting this command can serve +as a quick visual reminder. .TP 7 \ \ \'\fBy\fR\' :\fIRow_Highlight_toggle\fR Please use this toggle \*(EM highlight running tasks! -It's an important insight into your system's health and there is no extra -run-time cost associated with its use. -Besides, it is this provision alone that is largely responsible for -your-brand-new-top and you'll make the program author a happy guy. +It's an important insight into your system's health and it was largely this +provision that was responsible for your-brand-new-top. +You'll make the program author a happy guy. .TP 7 \ \ \'\fBz\fR\' :\fIColor/Monochrome_toggle\fR @@ -1030,7 +1032,7 @@ For additional information on these \*(CIs .TP 7 \ \ \'\fBS\fR\' :\fICumulative_Time_Mode_toggle\fR When 'Cumulative mode' is \*O, each process is listed with the \*(Pu -time that it\fB and\fR its dead children\fR has used. +time that it\fB and\fR its dead children\fR have used. When \*F, programs that fork into many separate tasks will appear less demanding. @@ -1079,7 +1081,7 @@ over the size of each currently visible \*(TD. .br .in +2 Before using any of these sort provisions, \*(Me suggests that you -\fItemporarily\fR turn on column highlighting using the '\fBx\fR' \*(CI. +temporarily turn on column highlighting using the '\fBx\fR' \*(CI. That will help ensure that the actual sort environment matches your intent. The following \*(CIs will\fB only\fR be honored when the @@ -1115,7 +1117,7 @@ be forced \*O when you return to the \*(Me display. However, depending upon your screen width and the order of your fields, this sort field may not be displayable. -These \*(CIs can be a convienent way to simply verify the current sort field, +This \*(CI can be a convienent way to simply verify the current sort field, when running \*(Me with column highlighting turned \*F. .TP 7 @@ -1133,6 +1135,12 @@ Try this:\ \ using 'R' you can\fI alternate\fR between high-to-low and low-to-high sorts. Lose no sleep over 'reverse' and 'normal', ok? +.PP +.in +2 +\*(NT Field sorting uses internal values, not those in column display. +Thus, the TTY and WCHAN fields will violate strict ASCII collating sequence. +.in + .\" ...................................................................... .SS 3d. COLOR Mapping .Scr @@ -1156,7 +1164,7 @@ in\fB all\fR four windows before returning to the \*(Me display. .Img +\fB--------------------------------------\fR+ - this shows you the |top's\fB Help for color mapping\fR - procps :\fB + this shows you the |\fBHelp for color mapping\fR - procps versio:\fB Target Window ----->\fR |current window:\fB 1:Def\fR : -*- | : a\fB Sample Screen\fR with | color - 04:25:44 up 8 days, 50 min,: @@ -1470,11 +1478,11 @@ empty rows... (when 2\fB WAS\fR current) | 683 1\fB xinetd -stayali\fR 0:00.00: |\fI___836_____1_\fBlogin_--_root\fI_____0:00.00\fR: 3:Mem has altered |\fI3__PID_%MEM__VIRT_SWAP__RES_CODE_DATA_\fR: - some std defaults: | 4634\fB 12.3\fR 15620 0\fB 15m\fR 860 14m : - 'y' turned Off | 7337\fB 11.3\fR 14396 92\fB 13m\fR 36 13m : - 'x' turned On | 923\fB 10.6\fR 30544 16m\fB 13m\fR 1120 12m : - (when 3\fB WAS\fR current) | 991\fB 7.2\fR 9492 316\fB 9176\fR 12 9164 : - |\fI__7329__\fB7.0\fI__9036__140_\fB8896\fR___36_8860_\fR: + some std defaults: | 4634\fB 12.3\fR 15620 0 15m 860 14m : + 'y' turned Off | 7337\fB 11.3\fR 14396 92 13m 36 13m : + 'x' turned On | 923\fB 10.6\fR 30544 16m 13m 1120 12m : + (when 3\fB WAS\fR current) | 991\fB 7.2\fR 9492 316 9176 12 9164 : + |\fI__7329__\fB7.0\fI__9036__140_8896___36_8860_\fR: Huh? 4:Usr has some |\fI4_UID_USER_____GROUP____TTY________PID\fR: \fBblank rows\fR! ? ? ? ? | \fB 0 jtwm root pts/2 5561\fR: Aha, the 'i' command | \fB 0 root root ? 5560\fR: @@ -1581,14 +1589,14 @@ seconds or less. For this experiment, under x-windows open an xterm and maximize it. Then do the following: - . provide a scheduling boost + tiny delay via: + . provide a scheduling boost and tiny delay via: nice -n -10 top -d.09 - . keep sorted column highlighting \*F - to minimize path length + . keep sorted column highlighting \*F to minimize + path length . turn \*O reverse row highlighting for emphasis . try various sort columns (TIME/MEM work well), - and normal or reverse sorts to bring - the most active processes into view + and normal or reverse sorts to bring the most + active processes into view What you'll see is a\fB very busy Linux\fR doing what he's always done for you, but there was no program available to illustrate this (until now). @@ -1650,39 +1658,91 @@ Then ponder this: .SH 7. NOTES and Rantings .\" ---------------------------------------------------------------------- .\" ...................................................................... -.SS 7a. The top BINARY -To whom it may/\fBshould\fR concern: \*(Us, even with its vastly expanded -capabilities, is essentially the same size as the old top. +.SS 7a. The top Binary +.PP +To whom it may (should) concern: \*(Us, even with its vastly expanded +capabilities, is only slightly larger than the old top. Were it not for extensive help text and additional sort callbacks, it would be smaller. .Rjb 6 Throw source carelessly at objectives, it\fI will\fR - produce equally careless machine instructions! + produce equally careless machine instructions. example: (num_\fBpages\fR - an_\fBaddress\fR)/1024 == duh? kicker: \fBdocument\fR result as broken, due to\fB elf\fR! \fB----------------------------------------------\fR I know you're out there, are you getting this? .Rje +.PP Now, as for all those new capabilities like colors and windows and -highlighting, just what are the\fB additional\fR run-time\fB costs\fR? -.br -Hmmm, let's see... +highlighting, you'd expect \*(Us to be the "mother of all pigs" +compared to old \*(Me \*(EM right? +Yea, with \*(US expect following piglets: +.br +\ \. A\fI smaller\fR virtual image and resident footprint +.br +\ \. Slightly\fI fewer\fR major page faults +.br +\ \. A\fI large reduction\fR in minor page faults for SMP +.br +\ \. The\fI same\fR or better response time +.br +\ \. The same or\fI even less\fR \*(PU costs + +Ideally any comparison of the old and new \*(Me should be against the same +libproc format (32-bit or 64-bit tics) and run in a true or simulated SMP +environment (producing separate \*(PU stats). +This latter requirement will coax old \*(Me into handling his own '/proc/stat' +access \*(EM something \*(Us always does, but with less cost. + +.\" ...................................................................... +.SS 7b. Comparing Performance +.PP +Even with equivalent libraries and '/proc/stat' access, it's difficult to +accurately compare tops using their \fBown displays\fR. +Results for these \*(Pu\-intensive programs (who frequently exceed their +time-slice) generally show a wide disparity in %CPU. +This is due to differing call patterns, kernel preemptions and the timing +of process snapshots. +For\fI slightly\fR better results, start each program with the following +commands: + ./old-top -d 0.5 + nice -n-10 ./new-top -d 0.4 + +While actually putting \*(Us at a performance disadvantage, the higher +scheduling priority and staggered timing will\fI periodically\fR yield +a somewhat truer picture. +You could even reverse those roles and get similar results. + +The most\fI consistent\fR performance results will be obtained 'off-line', +using your shell's time pipe or the time program itself. +And even in a single processor environment or without equivalent libraries, +total cpu costs (user time + system time) are similar. + +However, \*(Us's \*(Pu costs ARE influenced by the capabilities you choose +to exploit, even if they don't SEEM to be reflected in such timings. +So let's examine some... + +.\" ...................................................................... +.SS 7c. Cost of Stuff .TP 3 -.B Colors\fR \*(EM Nada. +.B Colors Cost\fR \*(EM Nada (almost). Once the terminfo strings are built (\fIat\fR and\fI during\fR a user's behest) they are SAVED with each window's stuff. -And while there will be a few extra tty escape sequences transmitted because -of colors, it makes NO difference which 'char *' is actually used. +And while there will be extra tty escape sequences transmitted because +of colors, it makes no difference which 'char *' is actually used. .TP 3 -.B Highlighting\fR \*(EM Maybe Nada, or blame it on Rio. +.B Highlighting Cost\fR \*(EM Nada (maybe), or blame it on Rio. On second thought, let's blame it on the user. -For\fI row\fR highlighting, there is NO extra cost (same reason as for colors). -For\fI column\fR highlighting, there is a fairly\fB significant cost\fR for -column transition management incurred on every \*(TD row. +For\fI row\fR highlighting, there is only the cost of those extra tty +escape sequences (same as for colors). +For\fI column\fR highlighting, there is a fairly\fB significant cost\fR +associated with column transition management combined with even more +tty output. +These increased costs are incurred on every \*(TD row. Sooo... hey USER \*(EM \fIdo NOT highlight COLUMNS\fR. You shouldn't need a constant visual reminder of your chosen sort field. @@ -1690,7 +1750,7 @@ However, if you forget which field \*(Me is sorting it can serve as a quick visual reminder. .TP 3 -.B Windows\fR \*(EM If just 1 window, Nada. +.B Windows Cost\fR \*(EM Nada (if just 1 window). If more than 1 window, almost certainly NOT Nada so blame it on reality. Colors are not an issue, but those sort fields are. @@ -1705,9 +1765,9 @@ Those sorts involve\fB pointers only\fR. And,\fI that's as good as it gets\fR\ !\ \ (right Mr. N?) .\" ...................................................................... -.SS 7b. The top SOURCES +.SS 7d. The top Sources .TP 3 -.B top.h\fR: +.B top.h\fR Unlike his predecessor, \*(Us has a proper header file. It contains ONLY declarations, NOT definitions. And there are several conditionals present to help with further customizations @@ -1715,9 +1775,8 @@ and experimentation. All are \*F by default. .TP 3 -.B top.c\fR: -Hopefully proves that source code needn't be a disorganized, -misaligned MESS. +.B top.c\fR +Hopefully proves that source code needn't be a disorganized, misaligned MESS. And, WHO says a source listing shouldn't occasionally make you SMILE? Why, \*(Me.c even does a darn good job of following the suggestions in a document hardly anybody seems to observe. @@ -1816,7 +1875,7 @@ Plus, without those awful *the-devil's-own-handiwork*, the aforementioned document need NEVER speak of their EVILS again. .Jbu -Lastly, since SPACES (not\fB stinkin' tabs\fR) are SO beneficial, maybe +Lastly, since SPACES (not stinkin' tabs) are SO beneficial, maybe we should use just a\fB few more\fR of 'em. Some of those C-thingies are VERY sensitive \*(EM they don't like being TOUCHED by any other syntax element! @@ -1890,8 +1949,8 @@ With invaluable help from: .\" ---------------------------------------------------------------------- .SH 11. SEE ALSO .\" ---------------------------------------------------------------------- -.BR ps (1), .BR free (1), +.BR ps (1), .BR uptime (1), .BR vmstat (8), .BR w (1). diff --git a/top.c b/top.c index 0be71daf..0d0e2d9f 100644 --- a/top.c +++ b/top.c @@ -123,8 +123,6 @@ static int No_ksyms = -1, /* set to '0' if ksym avail, '1' otherwise */ Loops = -1, /* number of iterations, -1 loops forever */ Secure_mode = 0; /* set if some functionality restricted */ - /* Miscellaneous global stuff ####################################*/ - /* Some cap's stuff to reduce runtime calls -- to accomodate 'Batch' mode, they begin life as empty strings */ static char Cap_bold [CAPBUFSIZ] = "", @@ -139,10 +137,6 @@ static char Cap_bold [CAPBUFSIZ] = "", Caps_off [CAPBUFSIZ] = ""; static int Cap_can_goto = 0; - /* Just to get gcc off our back and eliminate warnings about - '... discards qualifiers from pointer target type' */ -static char Empty_str[] = ""; -static char Question_mark[] = "?"; /* ////////////////////////////////////////////////////////////// */ /* Special Section: multiple windows/field groups ---------------*/ @@ -165,10 +159,14 @@ static int Frame_maxtask, /* last known number of active tasks */ /*###### Sort callbacks ################################################*/ - /* These happen to be coded in the same order as the enum 'pflag' - values -- but the only positionally dependent sort callback is - the 'pid' guy who MAY be invoked under return SORT_eq - (2 of these routines serve double duty -- 2 columns each) */ + /* + * These happen to be coded in the same order as the enum 'pflag' + * values -- but the only positionally dependent sort callback is + * the 'pid' guy who MAY be invoked under 'return SORT_eq' and + * thus must be first. + * + * Note: 2 of these routines serve double duty -- 2 columns each. + */ _SC_NUM1(P_PID, pid) _SC_NUM1(P_PPD, ppid) _SC_NUM1(P_PGD, pgrp) @@ -275,16 +273,15 @@ static const char *fmtmk (const char *fmts, ...) /* - * What need be said... */ + * This guy was originally designed just to trim the rc file lines and + * any 'open_psdb_message' result which arrived with an inappropriate + * newline (thanks to 'sysmap_mmap') -- but when tabs (^I) were found + * in some proc cmdlines, a choice was offered twix space or null. */ static char *strim (int sp, char *str) { - const char *ws = "\b\f\n\r\t\v"; + static const char *ws = "\b\f\n\r\t\v"; char *p; - /* this guy was originally designed just to trim the rc file lines and - any 'open_psdb_message' result which arrived with an inappropriate - newline (thanks to 'sysmap_mmap') -- but when tabs (^I) were found - in some proc cmdlines, a choice was offered twix space or null... */ if (sp) while ((p = strpbrk(str, ws))) *p = ' '; else @@ -294,10 +291,12 @@ static char *strim (int sp, char *str) /* - * This guy just facilitates Batch and protects against dumb ttys. */ + * This guy just facilitates Batch and protects against dumb ttys + * -- we'd 'inline' him but he's only called twice per frame, + * yet used in many other locations. */ static char *tg2 (int x, int y) { - return Cap_can_goto ? tgoto(cursor_address, x, y) : Empty_str; + return Cap_can_goto ? tgoto(cursor_address, x, y) : ""; } @@ -321,7 +320,7 @@ static void bye_bye (int eno, const char *str) "\nbye_bye's Summary report:" "\n\tProgram" "\n\t Page_size = %d, Cpu_tot = %d" - "\n\t %s, Hertz = %u (size %u bytes, %u-bit time)" + "\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)" "\n\t CPU_FMTS_JUST1 = %s" " \t CPU_FMTS_MULTI = %s" @@ -424,7 +423,7 @@ static void suspend (int dont_care_sig) } -/*###### Misc Color/Highlighting support ###############################*/ +/*###### Misc Color/Display support ####################################*/ /* * Make the appropriate caps/color strings and set some @@ -612,7 +611,7 @@ static void show_special (const char *glob) /* 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 (strlen(glob)) printf("%.*s", Screen_cols, glob); + if (*glob) printf("%.*s", Screen_cols, glob); fflush(stdout); } @@ -709,7 +708,7 @@ static char *scale_num (unsigned num, const unsigned width, const unsigned type) return buf; } /* well shoot, this outta' fit... */ - return Question_mark; + return "?"; } @@ -734,12 +733,12 @@ static char *scale_tics (TICS_t tics, const unsigned width) /* try successively higher units until it fits */ t = tics / Hertz; - sprintf(buf, "%u:%02u.%02u" /* minutes:seconds.hundredths */ - , t/60, t%60, (unsigned)((tics*100)/Hertz)%100); + sprintf(buf, "%u:%02u.%02u" /* mins:secs.hundredths */ + , t / 60, t % 60, (unsigned)((tics * 100) / Hertz) % 100); if (strlen(buf) <= width) return buf; - sprintf(buf, "%u:%02u", t/60, t%60); /* minutes:seconds */ + sprintf(buf, "%u:%02u", t / 60, t % 60); /* minutes:seconds */ if (strlen(buf) <= width) return buf; @@ -751,7 +750,7 @@ static char *scale_tics (TICS_t tics, const unsigned width) return buf; }; /* well shoot, this outta' fit... */ - return Question_mark; + return "?"; } @@ -779,7 +778,6 @@ static float time_elapsed (void) /* * Handle our own memory stuff without the risk of leaving the * user's terminal in an ugly state should things go sour. */ -static const char *alloc_msg = "Failed memory allocate (%d bytes)"; static void *alloc_c (unsigned numb) { @@ -787,7 +785,7 @@ static void *alloc_c (unsigned numb) if (!numb) ++numb; if (!(p = calloc(1, numb))) - std_err(fmtmk(alloc_msg, numb)); + std_err("failed memory allocate"); return p; } @@ -798,13 +796,59 @@ static void *alloc_r (void *q, unsigned numb) if (!numb) ++numb; if (!(p = realloc(q, numb))) - std_err(fmtmk(alloc_msg, numb)); + std_err("failed memory allocate"); return p; } /* - * This guy is modeled on libproc's readproctab function except + * This guy's modeled on libproc's 'four_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 + * cpus[Cpu_tot] == tics from the 1st /proc/stat line */ +static CPUS_t *refreshcpus (CPUS_t *cpus) +{ +#include + static FILE *fp = NULL; + int i; + + /* by opening this file once, we'll avoid the hit on minor page faults + (sorry Linux, but you'll have to close it for us) */ + if (!fp) { + if (!(fp = fopen("/proc/stat", "r"))) + std_err(fmtmk("Failed /proc/stat open: %s", strerror(errno))); + /* note: we allocate one more CPUS_t than Cpu_tot so that the last slot + can hold tics representing the /proc/stat cpu summary (the first + line read) -- that slot supports our View_CPUSUM toggle */ + cpus = alloc_c((1 + Cpu_tot) * sizeof(CPUS_t)); + } + rewind(fp); + fflush(fp); + + /* first value the last slot with the cpu summary line */ + if (4 != fscanf(fp, CPU_FMTS_JUST1 + , &cpus[Cpu_tot].u, &cpus[Cpu_tot].n, &cpus[Cpu_tot].s, &cpus[Cpu_tot].i)) + std_err("failed /proc/stat read"); + + /* and now value each separate cpu's tics */ + for (i = 0; i < Cpu_tot; i++) { +#ifdef PRETEND4CPUS + rewind(fp); + if (4 != fscanf(fp, CPU_FMTS_JUST1 +#else + if (4 != fscanf(fp, CPU_FMTS_MULTI +#endif + , &cpus[i].u, &cpus[i].n, &cpus[i].s, &cpus[i].i)) + std_err("failed /proc/stat read"); + } + + return 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 */ static proc_t **refreshprocs (proc_t **tbl) @@ -933,7 +977,7 @@ static void configs_read (void) fgets(fbuf, sizeof(fbuf), fp); /* ignore shameless advertisement */ if (5 != (fscanf(fp, "Id:%c, " "Mode_altscr=%d, Mode_irixps=%d, Delay_time=%f, Curwin=%d\n" - , &id, &Mode_altscr, &Mode_irixps, &delay, &i))) + , &id, &Mode_altscr, &Mode_irixps, &delay, &i)) || RCF_FILEID != id) std_err(fmtmk(err_rc, RCfile)); /* you saw that, right? (fscanf stickin' it to 'i') */ @@ -951,7 +995,7 @@ static void configs_read (void) then we catch it with strlen and end via std_err - no worries! we might not have been so lucky if our WIN_t was laid out differently and statically allocated or stack based!! */ - if (RCF_FILEID != id || WINNAMSIZ <= strlen(Winstk[i]->winname) + if (WINNAMSIZ <= strlen(Winstk[i]->winname) || strlen(DEF_FIELDS) != strlen(Winstk[i]->fieldscur)) std_err(fmtmk(err_rc, RCfile)); fscanf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d \n" @@ -989,7 +1033,8 @@ 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? */ - const char *usage = " -hv | -bcisS -d delay -n iterations -p pid [,pid ...]\n"; + static const char *usage = + " -hv | -bcisS -d delay -n iterations -p pid [,pid ...]"; float tmp_delay = MAXFLOAT; char *p; @@ -1017,7 +1062,7 @@ static void parse_args (char **args) break; case 'h': case 'H': case 'v': case 'V': - std_err(fmtmk("\t%s\nusage:\t%s%s" + std_err(fmtmk("%s\nusage:\t%s%s" , procps_version, Myname, usage)); case 'i': TOGw(Curwin, Show_IDLEPS); @@ -1083,14 +1128,14 @@ static void whack_terminal (void) /* first the curses part... */ #ifdef PRETENDNOCAP - setupterm((char *)"dumb", STDOUT_FILENO, NULL); + setupterm("dumb", STDOUT_FILENO, NULL); #else setupterm(NULL, STDOUT_FILENO, NULL); #endif /* now our part... */ if (!Batch) { if (-1 == tcgetattr(STDIN_FILENO, &Savedtty)) - std_err("tcgetattr() failed"); + std_err("failed tty get"); newtty = Savedtty; newtty.c_lflag &= ~ICANON; newtty.c_lflag &= ~ECHO; @@ -1100,7 +1145,7 @@ static void whack_terminal (void) Ttychanged = 1; if (-1 == tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtty)) { putp(Cap_clr_scr); - std_err(fmtmk("Failed tty set: %s", strerror(errno))); + std_err(fmtmk("failed tty set: %s", strerror(errno))); } tcgetattr(STDIN_FILENO, &Rawtty); putp(Cap_clr_scr); @@ -1208,7 +1253,7 @@ static void display_fields (const char *fields, const char *xtra) static void fields_reorder (void) { static const char *prompt = - "Upper case characters move field left, lower case right"; + "Upper case letter moves field left, lower case right"; char c, *p; int i; @@ -1241,10 +1286,10 @@ static void fields_sort (void) "Select sort field via field letter, type any other key to return"; char phoney[PFLAGSSIZ]; char c, *p; - int i; + int i, x; strcpy(phoney, NUL_FIELDS); - i = Curwin->sortindx; + x = i = Curwin->sortindx; printf("%s%s", Cap_clr_scr, Cap_curs_huge); do { p = phoney + i; @@ -1256,10 +1301,11 @@ static void fields_sort (void) i = toupper(c) - 'A'; if (i < 0 || i >= MAXTBL(Fieldstab)) break; *p = tolower(*p); - if ((p = strchr(Curwin->fieldscur, i + 'a'))) - *p = i + 'A'; - Curwin->sortindx = i; + x = i; } while (1); + if ((p = strchr(Curwin->fieldscur, x + 'a'))) + *p = x + 'A'; + Curwin->sortindx = x; putp(Cap_curs_norm); } @@ -1302,7 +1348,7 @@ static void win_colsheads (WIN_t *q) int i, needpsdb = 0; /* build window's procflags array and establish a tentative maxpflgs */ - for (i = 0, q->maxpflgs = 0; i < (int)strlen(q->fieldscur); i++) { + for (i = 0, q->maxpflgs = 0; q->fieldscur[i]; i++) { if (isupper(q->fieldscur[i])) q->procflags[q->maxpflgs++] = q->fieldscur[i] - 'A'; } @@ -1321,7 +1367,6 @@ static void win_colsheads (WIN_t *q) column heading via maxcmdln -- it may be a fib if P_CMD wasn't encountered, but that's ok because it won't be displayed anyway */ q->maxpflgs = i; - q->procflags[i] = '\0'; q->maxcmdln = Screen_cols - (strlen(q->columnhdr) - strlen(Fieldstab[P_CMD].head)) - 1; @@ -1398,8 +1443,8 @@ static void win_select (int ch) * Just warn the user when a command can't be honored. */ static int win_warn (void) { - show_msg(fmtmk("\aCommand disabled, activate window #%d with '-' or '_'" - , Curwin->winnum)); + show_msg(fmtmk("\aCommand disabled, activate %s with '-' or '_'" + , Curwin->grpname)); /* we gotta' return false 'cause we're somewhat well known within macro society, by way of that sassy little tertiary operator... */ return 0; @@ -1514,27 +1559,20 @@ static void wins_reflag (int what, int flg) TOGw(w, flg); break; case Flags_SET: /* Ummmm, i can't find anybody */ - SETw(w, flg); /* who uses Flags_set -- maybe */ - break; /* ol' gcc will opt it away... */ + SETw(w, flg); /* who uses Flags_set ... */ + break; case Flags_OFF: OFFw(w, flg); break; } - w = w->next; - } while (w != Curwin); - - /* a flag with special significance -- user wants to rebalance display - so darn it, we gotta' spin thru all those windows one mo' time and - 'off' one number then force on two flags... */ - /* (jeeze, doesn't this idiot know there are just 4 windows?) */ - if (EQUWINS_cwo == flg) { - w = Curwin; - do { + /* a flag with special significance -- user wants to rebalance + display so we gotta' 'off' one number then force on two flags... */ + if (EQUWINS_cwo == flg) { w->maxtasks = 0; SETw(w, Show_IDLEPS | VISIBLE_tsk); - w = w->next; - } while (w != Curwin); - } + } + w = w->next; + } while (w != Curwin); } @@ -1564,8 +1602,8 @@ static void wins_resize (int dont_care_sig) /* * Set up the raw/incomplete field group windows -- * they'll be finished off after startup completes. - * (and very likely that will override most/all of our efforts) - * ( --- life-is-NOT-fair --- ) */ + * [ and very likely that will override most/all of our efforts ] + * [ --- life-is-NOT-fair --- ] */ static void windows_stage1 (void) { static struct { @@ -1629,7 +1667,7 @@ static void windows_stage2 (void) if (Batch) { Mode_altscr = 0; - OFFw(Curwin, Show_COLORS); + OFFw(Curwin, Show_COLORS | Show_HICOLS | Show_HIROWS); } wins_resize(0); for (i = 0; i < GROUPSMAX; i++) { @@ -1649,25 +1687,17 @@ static void windows_stage2 (void) * 2 - modest smp boxes with room for each cpu's percentages * 3 - massive smp guys leaving little or no room for process * display and thus requiring the cpu summary toggle */ -static void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx) +static void cpudo (CPUS_t *cpu, const char *pfx) { /* we'll trim to zero if we get negative time ticks, which has happened with some SMP kernels (pre-2.4?) */ #define TRIMz(x) ((tz = (STIC_t)x) < 0 ? 0 : tz) - TICS_t u_tics, s_tics, n_tics, i_tics; STIC_t u_frme, s_frme, n_frme, i_frme, tot_frme, tz; -#ifdef PRETEND4CPUS - rewind(fp); - fmt = CPU_FMTS_JUST1; -#endif - if (4 != fscanf(fp, fmt, &u_tics, &n_tics, &s_tics, &i_tics)) - std_err("Failed /proc/stat read"); - - u_frme = TRIMz(u_tics - cpu->u); - s_frme = TRIMz(s_tics - cpu->s); - n_frme = TRIMz(n_tics - cpu->n); - i_frme = TRIMz(i_tics - cpu->i); + u_frme = TRIMz(cpu->u - cpu->u_sav); + s_frme = TRIMz(cpu->s - cpu->s_sav); + n_frme = TRIMz(cpu->n - cpu->n_sav); + i_frme = TRIMz(cpu->i - cpu->i_sav); tot_frme = u_frme + s_frme + n_frme + i_frme; if (1 > tot_frme) tot_frme = 1; @@ -1682,10 +1712,10 @@ static void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx) Msg_row += 1; /* remember for next time around */ - cpu->u = u_tics; - cpu->s = s_tics; - cpu->n = n_tics; - cpu->i = i_tics; + cpu->u_sav = cpu->u; + cpu->s_sav = cpu->s; + cpu->n_sav = cpu->n; + cpu->i_sav = cpu->i; #undef TRIMz } @@ -1696,11 +1726,10 @@ static void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx) * Calc percent cpu usage for each task (pcpu) * Calc the cpu(s) percent in each state (user, system, nice, idle) * AND establish the total number of tasks for this frame! */ -static void frame_states (proc_t **p, int show) +static void frame_states (proc_t **ppt, int show) { static HIST_t *hist_sav = NULL; static unsigned hist_siz; - static CPUS_t *smpcpu; HIST_t *hist_new; unsigned total, running, sleeping, stopped, zombie; float etime; @@ -1710,19 +1739,15 @@ static void frame_states (proc_t **p, int show) Frame_maxtask = 0; hist_siz = (Page_size / sizeof(HIST_t)); hist_sav = alloc_c(hist_siz); - /* note: we allocate one more CPUS_t than Cpu_tot so that the last - slot can hold tics representing the /proc/stat cpu summary - (first line read) -- that slot supports summary cpu info */ - smpcpu = alloc_c((1 + Cpu_tot) * sizeof(CPUS_t)); } hist_new = alloc_c(hist_siz); total = running = sleeping = stopped = zombie = 0; etime = time_elapsed(); /* make a pass through the data to get stats */ - while (-1 != p[total]->pid) { /* calculations //// */ + while (-1 != ppt[total]->pid) { /* calculations //// */ TICS_t tics; - proc_t *this = p[total]; + proc_t *this = ppt[total]; switch (this->state) { case 'S': @@ -1770,33 +1795,29 @@ static void frame_states (proc_t **p, int show) if (show) { /* display ///////// */ - FILE *fp; + static CPUS_t *smpcpu = NULL; /* display Task states */ show_special(fmtmk(STATES_line1 , total, running, sleeping, stopped, zombie)); Msg_row += 1; - if (!(fp = fopen("/proc/stat", "r"))) - std_err(fmtmk("Failed /proc/stat open: %s", strerror(errno))); + /* refresh our /proc/stat data... */ + smpcpu = refreshcpus(smpcpu); if (CHKw(Curwin, View_CPUSUM)) { - /* retrieve and display just the 1st /proc/stat line */ - cpudo(fp, CPU_FMTS_JUST1, &smpcpu[Cpu_tot], "Cpu(s) state:"); + /* display just the 1st /proc/stat line */ + cpudo(&smpcpu[Cpu_tot], "Cpu(s) state:"); } else { char tmp[SMLBUFSIZ]; - - /* skip the 1st line, which reflects total cpu states */ - if (!fgets(tmp, sizeof(tmp), fp)) std_err("Failed /proc/stat read"); - /* now do each cpu's states separately */ + /* display each cpu's states separately */ for (i = 0; i < Cpu_tot; i++) { sprintf(tmp, "%-6scpu%-2d:" /* [ cpu states as ] */ , i ? " " : "State" /* 'State cpu0 : ... ' */ , Mode_irixps ? i : Cpu_map[i]); /* ' cpu1 : ... ' */ - cpudo(fp, CPU_FMTS_MULTI, &smpcpu[i], tmp); + cpudo(&smpcpu[i], tmp); } } - fclose(fp); } /* end: if 'show' */ /* save this frame's information */ @@ -1819,7 +1840,7 @@ static void frame_storage (void) unsigned long long **memarray; if (!(memarray = meminfo())) - std_err("Failed /proc/meminfo read"); + std_err("failed /proc/meminfo read"); if (CHKw(Curwin, View_MEMORY)) { show_special(fmtmk(MEMORY_line1 @@ -1866,6 +1887,9 @@ static void mkcol (WIN_t *q, PFLG_t idx, int sta, int *pad, char *buf, ...) va_list va; va_start(va, buf); + /* this conditional is for piece-of-mind only, it should NOT be needed + given the macro employed by show_a_task (which calls us only when + the target column is the current sort field and Show_HICOLS is on) */ if (!CHKw(q, Show_HICOLS) || q->sortindx != idx) { vsprintf(buf, Fieldstab[idx].fmts, va); } else { @@ -1885,25 +1909,31 @@ static void mkcol (WIN_t *q, PFLG_t idx, int sta, int *pad, char *buf, ...) * Display information for a single task row. */ static void show_a_task (WIN_t *q, proc_t *task) { + /* the following macro is our means to 'inline' emitting a column -- that's + 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); \ + else mkcol(q, idx, sta, pad, buf, ## arg); char rbuf[ROWBUFSIZ]; - int i, x, pad; + int j, x, pad; /* since win_colsheads adds a number to the window's column header, we must begin a row with that in mind... */ pad = Mode_altscr; if (pad) strcpy(rbuf, " "); else rbuf[0] = '\0'; - for (i = 0; i < q->maxpflgs; i++) { - char cbuf[COLBUFSIZ]; - PFLG_t f; - unsigned s, w; + for (x = 0; x < q->maxpflgs; x++) { + char cbuf[COLBUFSIZ]; + char a = task->state; /* we'll use local var's so */ + PFLG_t i = q->procflags[x]; /* gcc doesn't reinvent the */ + unsigned s = Fieldstab[i].scale; /* wheel -- yields a cryptic */ + unsigned w = Fieldstab[i].width; /* mkcol, but saves +1k code */ + const char *f = Fieldstab[i].fmts; /* (this & next macro only) */ + int b = (CHKw(q, Show_HICOLS) && q->sortindx == i); cbuf[0] = '\0'; - f = q->procflags[i]; - s = Fieldstab[f].scale; - w = Fieldstab[f].width; - - switch (f) { + switch (i) { case P_CMD: { char *cmdptr, cmdnam[ROWBUFSIZ]; @@ -1912,104 +1942,98 @@ static void show_a_task (WIN_t *q, proc_t *task) else { cmdnam[0] = '\0'; if (task->cmdline) { - x = 0; + j = 0; do { /* during a kernel build, parts of the make will create cmdlines in excess of 3000 bytes but *without* the intervening nulls -- so we must limit our strcat... */ strcat(cmdnam - , fmtmk("%.*s ", q->maxcmdln, task->cmdline[x++])); + , fmtmk("%.*s ", q->maxcmdln, task->cmdline[j++])); /* whoa, gnome's xscreensaver had a ^I in his cmdline creating a line wrap when the window was maximized & the tab came into view -- so whack those suckers... */ strim(1, cmdnam); if (q->maxcmdln < (int)strlen(cmdnam)) break; - } while (task->cmdline[x]); + } while (task->cmdline[j]); } else { /* if cmdline is absent, consider it a kernel thread and - display it uniquely (we'll need sort_cmd's complicity) */ - strcpy(cmdnam, fmtmk("( %s )", task->cmd)); + display it uniquely (need sort callback's complicity) */ + strcpy(cmdnam, fmtmk(CMDLINE_FMTS, task->cmd)); } cmdptr = cmdnam; } - mkcol(q, f, task->state, &pad - , cbuf, q->maxcmdln, q->maxcmdln, cmdptr); + MKCOL(q, i, a, &pad, cbuf, q->maxcmdln, q->maxcmdln, cmdptr); } break; case P_COD: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(PAGES_2K(task->trs), w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(PAGES_2K(task->trs), w, s)); break; case P_CPN: #ifdef UGH_ITS_4_RH - mkcol(q, f, task->state, &pad, cbuf, task->lproc); + MKCOL(q, i, a, &pad, cbuf, task->lproc); #else - mkcol(q, f, task->state, &pad, cbuf, task->processor); + MKCOL(q, i, a, &pad, cbuf, task->processor); #endif break; case P_CPU: - mkcol(q, f, task->state, &pad, cbuf, (float)task->pcpu / 10); + MKCOL(q, i, a, &pad, cbuf, (float)task->pcpu / 10); break; case P_DAT: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(PAGES_2K(task->drs), w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(PAGES_2K(task->drs), w, s)); break; case P_DRT: - mkcol(q, f, task->state, &pad, cbuf - , scale_num((unsigned)task->dt, w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num((unsigned)task->dt, w, s)); break; case P_FLG: - mkcol(q, f, task->state, &pad, cbuf, task->flags); - for (x = 0; x < (int)strlen(cbuf); x++) - if ('0' == cbuf[x]) cbuf[x] = '.'; + MKCOL(q, i, a, &pad, cbuf, (long)task->flags); + for (j = 0; cbuf[j]; j++) + if ('0' == cbuf[j]) cbuf[j] = '.'; break; case P_FLT: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(task->maj_flt, w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(task->maj_flt, w, s)); break; case P_GRP: - mkcol(q, f, task->state, &pad, cbuf, task->egroup); + MKCOL(q, i, a, &pad, cbuf, task->egroup); break; case P_MEM: - mkcol(q, f, task->state, &pad, cbuf #ifdef UGH_ITS_4_RH + MKCOL(q, i, a, &pad, cbuf , (float)task->resident * 100 / Mem_pages); #else + MKCOL(q, i, a, &pad, cbuf , (float)PAGES_2K(task->resident) * 100 / kb_main_total); #endif break; case P_NCE: - mkcol(q, f, task->state, &pad, cbuf, task->nice); + MKCOL(q, i, a, &pad, cbuf, (long)task->nice); break; case P_PGD: - mkcol(q, f, task->state, &pad, cbuf, task->pgrp); + MKCOL(q, i, a, &pad, cbuf, task->pgrp); break; case P_PID: - mkcol(q, f, task->state, &pad, cbuf, task->pid); + MKCOL(q, i, a, &pad, cbuf, task->pid); break; case P_PPD: - mkcol(q, f, task->state, &pad, cbuf, task->ppid); + MKCOL(q, i, a, &pad, cbuf, task->ppid); break; case P_PRI: - mkcol(q, f, task->state, &pad, cbuf, task->priority); + MKCOL(q, i, a, &pad, cbuf, (long)task->priority); break; case P_RES: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(PAGES_2K(task->resident), w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(PAGES_2K(task->resident), w, s)); break; case P_SHR: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(PAGES_2K(task->share), w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(PAGES_2K(task->share), w, s)); break; case P_STA: #ifdef USE_LIB_STA3 - mkcol(q, f, task->state, &pad, cbuf, status(task)); + MKCOL(q, i, a, &pad, cbuf, status(task)); #else - mkcol(q, f, task->state, &pad, cbuf, task->state); + MKCOL(q, i, a, &pad, cbuf, task->state); #endif break; case P_SWP: - mkcol(q, f, task->state, &pad, cbuf + MKCOL(q, i, a, &pad, cbuf , scale_num(PAGES_2K(task->size - task->resident), w, s)); break; case P_TME: @@ -2019,40 +2043,38 @@ static void show_a_task (WIN_t *q, proc_t *task) t = task->utime + task->stime; if (CHKw(q, Show_CTIMES)) t += (task->cutime + task->cstime); - mkcol(q, f, task->state, &pad, cbuf, scale_tics(t, w)); + MKCOL(q, i, a, &pad, cbuf, scale_tics(t, w)); } break; case P_TTY: { char tmp[TNYBUFSIZ]; dev_to_tty(tmp, (int)w, task->tty, task->pid, ABBREV_DEV); - mkcol(q, f, task->state, &pad, cbuf, tmp); + MKCOL(q, i, a, &pad, cbuf, tmp); } break; case P_UID: - mkcol(q, f, task->state, &pad, cbuf, task->euid); + MKCOL(q, i, a, &pad, cbuf, task->euid); break; case P_USR: - mkcol(q, f, task->state, &pad, cbuf, task->euser); + MKCOL(q, i, a, &pad, cbuf, task->euser); break; case P_VRT: - mkcol(q, f, task->state, &pad, cbuf - , scale_num(PAGES_2K(task->size), w, s)); + MKCOL(q, i, a, &pad, cbuf, scale_num(PAGES_2K(task->size), w, s)); break; case P_WCH: - if (No_ksyms) + if (No_ksyms) { #ifdef CASEUP_HEXES - mkcol(q, f, task->state, &pad, cbuf - , fmtmk("x%08lX", (long)task->wchan)); + MKCOL(q, i, a, &pad, cbuf, fmtmk("x%08lX", (long)task->wchan)); #else - mkcol(q, f, task->state, &pad, cbuf - , fmtmk("x%08lx", (long)task->wchan)); + MKCOL(q, i, a, &pad, cbuf, fmtmk("x%08lx", (long)task->wchan)); #endif - else - mkcol(q, f, task->state, &pad, cbuf, wchan(task->wchan)); + } else { + MKCOL(q, i, a, &pad, cbuf, wchan(task->wchan)); + } break; - } /* end: switch 'flg' */ + } /* end: switch 'procflag' */ strcat(rbuf, cbuf); } /* end: for 'maxpflgs' */ @@ -2067,6 +2089,7 @@ static void show_a_task (WIN_t *q, proc_t *task) , Caps_off , Cap_clr_eol); +#undef MKCOL } @@ -2077,10 +2100,10 @@ static void show_a_task (WIN_t *q, proc_t *task) static void do_key (unsigned c) { /* standardized 'secure mode' errors */ - const char *err_secure = "\aCan't %s in secure mode"; + static const char *err_secure = "\aUnavailable in secure mode"; #ifdef WARN_NOT_SMP /* standardized 'smp' errors */ - const char *err_smp = "\aSorry, only 1 cpu detected"; + static const char *err_smp = "\aSorry, only 1 cpu detected"; #endif switch (c) { @@ -2122,7 +2145,7 @@ static void do_key (unsigned c) case 'd': case 's': if (Secure_mode) - show_msg(fmtmk(err_secure, "change delay")); + show_msg(err_secure); else { float tmp = get_float(fmtmk("Change delay from %.1f to", Delay_time)); @@ -2166,7 +2189,7 @@ static void do_key (unsigned c) /* this string is well above ISO C89's minimum requirements! */ show_special(fmtmk(KEYS_help , procps_version - , Curwin->winname + , Curwin->grpname , CHKw(Curwin, Show_CTIMES) ? "On" : "Off" , Delay_time , Secure_mode ? "On" : "Off" @@ -2208,7 +2231,7 @@ static void do_key (unsigned c) case 'k': if (Secure_mode) { - show_msg(fmtmk(err_secure, "kill")); + show_msg(err_secure); } else { int sig, pid = get_int("PID to kill"); @@ -2263,7 +2286,7 @@ static void do_key (unsigned c) case 'r': if (Secure_mode) - show_msg(fmtmk(err_secure, "renice")); + show_msg(err_secure); else { int pid, val; @@ -2356,32 +2379,24 @@ static void do_key (unsigned c) wins_colors(); break; - case '-': /* 'Dash' lower case ----------------------- */ + case '-': if (Mode_altscr) TOGw(Curwin, VISIBLE_tsk); break; - case '_': /* 'Dash' upper case ----------------------- */ - if (Mode_altscr) /* switcharoo, all viz & inviz ............ */ + case '_': + if (Mode_altscr) wins_reflag(Flags_TOG, VISIBLE_tsk); break; - case '=': /* 'Equals' lower case --------------------- */ - /* special Key: equalize current window (& make viz) ... - . began life as 'windows' oriented and restricted to Mode_altscr! - . but symbiosis of documenting and further testing led to lifting - of restrictions -- we feel MUCH better now, thank-you-SO-much! */ + case '=': Curwin->maxtasks = 0; SETw(Curwin, Show_IDLEPS | VISIBLE_tsk); - /* special Provision: - . escape from monitoring selected pids ('-p' cmdline switch) - -- just seems to go naturally with these new provisions - . and who knows, maybe the man doc will NOT be overlooked */ Monpidsidx = 0; break; - case '+': /* 'Equals' upper case --------------------- */ - if (Mode_altscr) /* equalize ALL task wins (& make viz) .... */ + case '+': + if (Mode_altscr) SETw(Curwin, EQUWINS_cwo); break; @@ -2403,8 +2418,8 @@ static void do_key (unsigned c) } break; - case '\n': /* just ignore these */ - case ' ': + case '\n': /* just ignore these, they'll have the effect */ + case ' ': /* of refreshing display after waking us up ! */ break; default: @@ -2449,7 +2464,7 @@ static proc_t **do_summary (void) /* ** Display Tasks and Cpu(s) states and also calc 'pcpu', - ** but NO p_table sort yet -- that's done on a per window basis! */ + ** but NO table sort yet -- that's done on a per window basis! */ p_table = refreshprocs(p_table); frame_states(p_table, CHKw(Curwin, View_STATES)); diff --git a/top.h b/top.h index 58aae8ff..caae8f92 100644 --- a/top.h +++ b/top.h @@ -27,6 +27,7 @@ //#define CASEUP_HEXES /* show any hex values in upper case */ //#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 QUIT_NORMALQ /* use 'q' to quit, not new default 'Q' */ //#define SORT_SUPRESS /* *attempt* to reduce qsort overhead */ //#define TICS_64_BITS /* accommodate Linux 2.5.xx 64-bit jiffies */ @@ -64,6 +65,7 @@ #define SMLBUFSIZ 256 #define MEDBUFSIZ 512 #define OURPATHSZ 1024 +#define STATBUFSZ 1024 #define BIGBUFSIZ 2048 #define RCFBUFSIZ SMLBUFSIZ #define USRNAMSIZ GETBUFSIZ @@ -105,7 +107,7 @@ if ( ((*P)->n1 - (*P)->n2) > ((*Q)->n1 - (*Q)->n2) ) return SORT_gt; \ return SORT_eq; } #define _SC_STRZ(f,s) \ - static int sort_ ## f(const proc_t **P, const proc_t **Q) { \ + static int sort_ ## f (const proc_t **P, const proc_t **Q) { \ if ( 0 > strcmp((*P)->s, (*Q)->s) ) return SORT_lt; \ if ( 0 < strcmp((*P)->s, (*Q)->s) ) return SORT_gt; \ return SORT_eq; } @@ -159,15 +161,18 @@ typedef struct { TICS_t tics; } HIST_t; - /* This structure stores the prior frame's tics used in history + /* This structure stores a frame's cpu tics used in history calculations. It exists primarily for SMP support but serves - all environments. There will always Cpu_tot + 1 allocated - -- see frame_states for details. */ + all environments. */ typedef struct { - TICS_t u, /* ticks count as represented in /proc/stat */ - n, /* (not in the order of our display) */ + TICS_t u, /* ticks count as represented in /proc/stat */ + n, /* (not in the order of our display) */ s, i; + TICS_t u_sav, /* tics count in the order of our display */ + s_sav, + n_sav, + i_sav; } CPUS_t; /* The scaling 'type' used with scale_num() -- this is how @@ -221,7 +226,7 @@ enum pflag { #define Show_IDLEPS 0x0020 /* 'i' - show idle processes (all tasks) */ #define Qsrt_NORMAL 0x0010 /* 'R' - reversed column sort (high to low) */ /* these flag(s) have no command as such - they're for internal use */ -#define VISIBLE_tsk 0x0008 /* tasks are showable in 'Show_altscr' mode */ +#define VISIBLE_tsk 0x0008 /* tasks are showable when in 'Mode_altscr' */ #define NEWFRAM_cwo 0x0004 /* new frame (if anyone cares) - in Curwin */ #define EQUWINS_cwo 0x0002 /* rebalance tasks next frame (off 'i'/ 'n') */ /* ...set in Curwin, but impacts all windows */ @@ -285,7 +290,7 @@ typedef struct win { /* An rcfile 'footprint' used to invalidate existing local rcfile and the global rcfile path + name */ -#define RCF_FILEID 'i' +#define RCF_FILEID 'j' #define SYS_RCFILE "/etc/toprc" /* The default fields displayed and their order, @@ -299,13 +304,22 @@ typedef struct win { #define NUL_FIELDS "abcdefghijklmnopqrstuvwxyz" /* These are the possible fscanf formats used in /proc/stat - reads during history processing. */ + reads during history processing. + ( 5th number added in anticipation of kernel change ) */ #ifdef TICS_64_BITS -#define CPU_FMTS_MULTI "cpu%*d %Lu %Lu %Lu %Lu\n" -#define CPU_FMTS_JUST1 "cpu %Lu %Lu %Lu %Lu\n" +#define CPU_FMTS_JUST1 "cpu %Lu %Lu %Lu %Lu \n" +#define CPU_FMTS_MULTI "cpu%*d %Lu %Lu %Lu %Lu %*d \n" #else -#define CPU_FMTS_MULTI "cpu%*d %lu %lu %lu %lu\n" -#define CPU_FMTS_JUST1 "cpu %lu %lu %lu %lu\n" +#define CPU_FMTS_JUST1 "cpu %lu %lu %lu %lu \n" +#define CPU_FMTS_MULTI "cpu%*d %lu %lu %lu %lu %*d \n" +#endif + + /* This is the format for 'command line' display in the absence + of a command line (kernel thread). */ +#ifdef POSIX_CMDLIN +#define CMDLINE_FMTS "[%s]" +#else +#define CMDLINE_FMTS "( %s )" #endif /* Summary Lines specially formatted string(s) -- @@ -343,14 +357,14 @@ typedef struct win { #endif #define KEYS_help \ "Help for Interactive Commands\02 - %s\n" \ - "Window %s\06: \01Cumulative mode \03%s\02. \01System\06: \01Delay time \03%.1f secs\02; \01Secure mode \03%s\02.\n" \ + "Window \01%s\06: \01Cumulative mode \03%s\02. \01System\06: \01Delay \03%.1f secs\02; \01Secure mode \03%s\02.\n" \ "\n" \ " l,t,m Toggle Summary: '\01l\02' load avg; '\01t\02' task/cpu stats; '\01m\02' mem info\n" \ " 1,I Toggle SMP view: '\0011\02' single/separate states; '\01I\02' Irix/Solaris mode\n" \ " Z\05 Change color mappings\n" \ "\n" \ - " f,o . Fields change: '\01f\02' fields select; '\01o\02' order fields\n" \ - " F or O . Fields select sort\n" \ + " f,o . Fields/Columns: '\01f\02' add or remove; '\01o\02' change display order\n" \ + " F or O . Select sort field\n" \ " <,> . Move sort field: '\01<\02' next col left; '\01>\02' next col right\n" \ " R . Toggle normal/reverse sort\n" \ " c,i,S . Toggle: '\01c\02' cmd name/line; '\01i\02' idle tasks; '\01S\02' cumulative time\n" \ @@ -358,16 +372,16 @@ typedef struct win { " z,b\05 . Toggle: '\01z\02' color/mono; '\01b\02' bold/reverse (only if 'x' or 'y')\n" \ " u . Show specific user only\n" \ " n or # . Set maximum tasks displayed\n" \ - " ( commands shown with '.' require a \01visible\02 task display \01window\02 ) \n" \ "\n" \ "%s" \ " W Write configuration file\n" \ HELP_Qkey "Quit\n" \ + " ( commands shown with '.' require a \01visible\02 task display \01window\02 ) \n" \ "Press '\01h\02' or '\01?\02' for help with \01Windows\02,\n" \ "any other key to continue " \ "" - /* This guy goes above the 'u' help text (maybe) */ + /* This guy goes into the help text (maybe) */ #define KEYS_help_unsecured \ " k,r Manipulate tasks: '\01k\02' kill; '\01r\02' renice\n" \ " d or s Set update interval\n" \ @@ -421,11 +435,11 @@ typedef struct win { " within viewable range is chosen.\n" \ "\n" \ "Note2:\n" \ - " The WCHAN field will display a name\n" \ - " if the System.map exists, but it is\n" \ - " always sorted as an address. Thus,\n" \ - " alphabetic sequence will not apply.\n" \ - " ( shame on you if you choose this )\n" \ + " Field sorting uses internal values,\n" \ + " not those in column display. Thus,\n" \ + " the TTY & WCHAN fields will violate\n" \ + " strict ASCII collating sequence.\n" \ + " (shame on you if WCHAN is chosen)\n" \ "" /* Colors Help specially formatted string(s) -- @@ -459,7 +473,7 @@ typedef struct win { /* Windows/Field Group Help specially formatted string(s) -- see 'show_special' for syntax details + other cautions. */ #define WINDOWS_help \ - "Help for Windows / Field Groups\02 - \"Current\" = \01 %s \06\n" \ + "Help for Windows / Field Groups\02 - \"Current Window\" = \01 %s \06\n" \ "\n" \ ". Use multiple \01windows\02, each with separate config opts (color,fields,sort,etc)\n" \ ". The 'current' window controls the \01Summary Area\02 and responds to your \01Commands\02\n" \ @@ -467,9 +481,9 @@ typedef struct win { " . with \01NO\02 task display, some commands will be \01disabled\02 ('i','R','n','c', etc)\n" \ " until a \01different window\02 has been activated, making it the 'current' window\n" \ ". You \01change\02 the 'current' window by: \01 1\02) cycling forward/backward;\01 2\02) choosing\n" \ - " a specific window with 'O' or 'F'; or\01 3\02) exiting the color mapping screen\n" \ + " a specific field group; or\01 3\02) exiting the color mapping screen\n" \ ". Commands \01available anytime -------------\02\n" \ - " \01A\02 . Alternate display mode toggle, show \01Single\02 / \01Multiple\02 windows\n" \ + " A . Alternate display mode toggle, show \01Single\02 / \01Multiple\02 windows\n" \ " G . Choose another field group and make it 'current', or change now\n" \ " by selecting a number from: \01 1\02 =%s;\01 2\02 =%s;\01 3\02 =%s; or\01 4\02 =%s\n" \ ". Commands \01requiring\02 '\01A\02' mode\01 -------------\02\n" \ @@ -482,7 +496,7 @@ typedef struct win { " (this also forces the \01current\02 or \01every\02 window to become visible)\n" \ "\n" \ "In '\01A\02' mode, '\01*\04' keys are your \01essential\02 commands. Please try the '\01a\02' and '\01w\02'\n" \ - "commands plus the 'F' sub-commands NOW. Press to make 'Current' " \ + "commands plus the 'G' sub-commands NOW. Press to make 'Current' " \ "" @@ -505,7 +519,7 @@ typedef struct win { //atic void stop (int dont_care_sig); //atic void std_err (const char *str); //atic void suspend (int dont_care_sig); -/*------ Misc Color/Highlighting support -------------------------------*/ +/*------ Misc Color/Display support ------------------------------------*/ //atic void capsmk (WIN_t *q); //atic void msg_save (const char *fmts, ...); //atic void show_msg (const char *str); @@ -521,6 +535,7 @@ typedef struct win { /*------ Library Alternatives ------------------------------------------*/ //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); /*------ Startup routines ----------------------------------------------*/ //atic void before (char *me); @@ -545,8 +560,8 @@ typedef struct win { //atic void windows_stage1 (void); //atic void windows_stage2 (void); /*------ Per-Frame Display support -------------------------------------*/ -//atic void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx); -//atic void frame_states (proc_t **p, int show); +//atic void cpudo (CPUS_t *cpu, const char *pfx); +//atic void frame_states (proc_t **ppt, int show); //atic void frame_storage (void); //atic void mkcol (WIN_t *q, PFLG_t idx, int sta, int *pad, char *buf, ...); //atic void show_a_task (WIN_t *q, proc_t *task);