top(1): reimplement header formatting as sbuf

The current header formatting is a giant format string that changes
global state during the format process.

Make the following changes:
- use sbuf to build up the header rather than use the above
pseudo-dynamic one
- Change name length to 10
- Reduce size of RES and SIZE by making humanize more aggressive
- Restore a version number line to the copyright. This may be required
by the copyright (and may not be; its unclear)

This is also a pre-req to implementing TOPCOLOR from newer versions of
top(1)

Discussed with:	allanjude, rpolka, danfe, rgrimes
Differential Revision: https://reviews.freebsd.org/D15801
This commit is contained in:
eadler 2018-06-22 09:21:01 +00:00
parent 9e86e7ede7
commit df25a45659
5 changed files with 47 additions and 85 deletions

View File

@ -16,5 +16,5 @@ NO_WERROR=
.endif
CFLAGS.clang=-Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=cast-qual
LIBADD= ncursesw m kvm jail util
LIBADD= ncursesw m kvm jail util sbuf
.include <bsd.prog.mk>

View File

@ -1,5 +1,6 @@
/*
* Top users/processes display for Unix
* Version 3
*
* This program may be freely redistributed,
* but this entire comment MUST remain intact.

View File

@ -22,6 +22,7 @@
#include <sys/priority.h>
#include <sys/proc.h>
#include <sys/resource.h>
#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/user.h>
@ -49,18 +50,14 @@
#include "layout.h"
#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
#define SMPUNAMELEN 13
#define UPUNAMELEN 15
extern struct timeval timeout;
static int smpmode;
enum displaymodes displaymode;
static int namelength = 8;
static const int namelength = 10;
/* TOP_JID_LEN based on max of 999999 */
#define TOP_JID_LEN 7
#define TOP_SWAP_LEN 6
static int jidlength;
static int swaplength;
#define TOP_JID_LEN 6
#define TOP_SWAP_LEN 5
static int cmdlengthdelta;
/* get_process_info passes back a handle. This is what it looks like: */
@ -92,23 +89,11 @@ static const char io_header[] =
static const char io_Proc_format[] =
"%5d%*s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s";
/* XXX: build up header instead of statically defining them.
* This will also allow for a "format string" to be supplied
* as an argument to top(1) instead of having predefined options */
static const char smp_header_thr_and_pid[] =
" %s%*s %-*.*s THR PRI NICE SIZE RES%*s STATE C TIME %7s COMMAND";
static const char smp_header_id_only[] =
" %s%*s %-*.*s PRI NICE SIZE RES%*s STATE C TIME %7s COMMAND";
static const char smp_Proc_format[] =
"%5d%*s %-*.*s %s%3d %4s%7s %6s%*.*s %-6.6s %2d%7s %6.2f%% %.*s";
"%5d%*s %-*.*s %s%3d %4s%6s %5s%*.*s %-6.6s %2d%7s %6.2f%% %.*s";
static char up_header_thr_and_pid[] =
" %s%*s %-*.*s THR PRI NICE SIZE RES%*s STATE TIME %7s COMMAND";
static char up_header_id_only[] =
" %s%*s %-*.*s PRI NICE SIZE RES%*s STATE TIME %7s COMMAND";
static char up_Proc_format[] =
"%5d%*s %-*.*s %s%3d %4s%7s %6s%*.*s %-6.6s%.0d%7s %6.2f%% %.*s";
"%5d%*s %-*.*s %s%3d %4s%6s %5s%*.*s %-6.6s%.0d%7s %6.2f%% %.*s";
/* process state names for the "STATE" column of the display */
/* the extra nulls in the string "run" are for adding a slash and
@ -325,12 +310,6 @@ machine_init(struct statics *statics)
NULL, 0) == 0 && carc_en == 1)
carc_enabled = 1;
namelength = MAXLOGNAME;
if (smpmode && namelength > SMPUNAMELEN)
namelength = SMPUNAMELEN;
else if (namelength > UPUNAMELEN)
namelength = UPUNAMELEN;
kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
if (kd == NULL)
return (-1);
@ -407,63 +386,46 @@ machine_init(struct statics *statics)
return (0);
}
const char *
char *
format_header(const char *uname_field)
{
static char Header[128];
const char *prehead;
static struct sbuf* header = NULL;
if (ps.jail)
jidlength = TOP_JID_LEN + 1; /* +1 for extra left space. */
else
jidlength = 0;
if (ps.swap)
swaplength = TOP_SWAP_LEN + 1; /* +1 for extra left space */
else
swaplength = 0;
/* clean up from last time. */
if (header != NULL) {
sbuf_delete(header);
}
header = sbuf_new_auto();
switch (displaymode) {
case DISP_CPU:
/*
* The logic of picking the right header is confusing, and
* depends on too much. We should instead have a struct of
* "header name", and "header format" which we build up.
* This would also fix the duplicate of effort into up vs smp
* mode.
*/
if (smpmode) {
prehead = ps.thread ?
smp_header_id_only : smp_header_thr_and_pid;
snprintf(Header, sizeof(Header), prehead,
ps.thread_id ? " THR" : "PID",
jidlength, ps.jail ? " JID" : "",
namelength, namelength, uname_field,
swaplength, ps.swap ? " SWAP" : "",
ps.wcpu ? "WCPU" : "CPU");
} else {
prehead = ps.thread ?
up_header_id_only : up_header_thr_and_pid;
snprintf(Header, sizeof(Header), prehead,
ps.thread_id ? " THR" : "PID",
jidlength, ps.jail ? " JID" : "",
namelength, namelength, uname_field,
swaplength, ps.swap ? " SWAP" : "",
ps.wcpu ? "WCPU" : "CPU");
}
case DISP_CPU: {
sbuf_printf(header, " %s", ps.thread_id ? " THR" : "PID");
sbuf_printf(header, "%*s", ps.jail ? TOP_JID_LEN : 0,
ps.jail ? " JID" : "");
sbuf_printf(header, " %-*.*s", namelength, namelength, uname_field);
sbuf_cat(header, " THR PRI NICE SIZE RES");
sbuf_printf(header, "%*s", ps.swap ? TOP_SWAP_LEN : 0,
ps.swap ? " SWAP" : "");
sbuf_printf(header, "%s", smpmode ? " STATE C " : " STATE ");
sbuf_cat(header, "TIME");
sbuf_printf(header, " %7s", ps.wcpu ? "WCPU" : "CPU");
sbuf_cat(header, " COMMAND");
sbuf_finish(header);
break;
case DISP_IO:
prehead = io_header;
snprintf(Header, sizeof(Header), prehead,
}
case DISP_IO: {
sbuf_printf(header, io_header,
ps.thread_id ? " THR" : "PID",
jidlength, ps.jail ? " JID" : "",
ps.jail ? TOP_JID_LEN : 0, ps.jail ? " JID" : "",
namelength, namelength, uname_field);
break;
}
case DISP_MAX:
assert("displaymode must not be set to DISP_MAX");
}
cmdlengthdelta = strlen(Header) - 7;
return (Header);
cmdlengthdelta = sbuf_len(header) - 7;
return sbuf_data(header);
}
static int swappgsin = -1;
@ -923,7 +885,7 @@ format_next_process(void* xhandle, char *(*get_userid)(int), int flags)
long p_tot, s_tot;
const char *proc_fmt;
char thr_buf[6];
char jid_buf[TOP_JID_LEN + 1], swap_buf[TOP_SWAP_LEN + 1];
char jid_buf[TOP_JID_LEN], swap_buf[TOP_SWAP_LEN];
char *cmdbuf = NULL;
char **args;
const int cmdlen = 128;
@ -1081,13 +1043,13 @@ format_next_process(void* xhandle, char *(*get_userid)(int), int flags)
jid_buf[0] = '\0';
else
snprintf(jid_buf, sizeof(jid_buf), "%*d",
jidlength - 1, pp->ki_jid);
TOP_JID_LEN - 1, pp->ki_jid);
if (ps.swap == 0)
swap_buf[0] = '\0';
else
snprintf(swap_buf, sizeof(swap_buf), "%*s",
swaplength - 1,
TOP_SWAP_LEN - 1,
format_k(pagetok(ki_swap(pp)))); /* XXX */
if (displaymode == DISP_IO) {
@ -1109,7 +1071,7 @@ format_next_process(void* xhandle, char *(*get_userid)(int), int flags)
snprintf(fmt, sizeof(fmt), io_Proc_format,
pp->ki_pid,
jidlength, jid_buf,
ps.jail ? TOP_JID_LEN : 0, jid_buf,
namelength, namelength, (*get_userid)(pp->ki_ruid),
rup->ru_nvcsw,
rup->ru_nivcsw,
@ -1142,16 +1104,17 @@ format_next_process(void* xhandle, char *(*get_userid)(int), int flags)
snprintf(thr_buf, sizeof(thr_buf), "%*d ",
(int)(sizeof(thr_buf) - 2), pp->ki_numthreads);
snprintf(fmt, sizeof(fmt), proc_fmt,
(ps.thread_id) ? pp->ki_tid : pp->ki_pid,
jidlength, jid_buf,
ps.jail ? TOP_JID_LEN : 0, jid_buf,
namelength, namelength, (*get_userid)(pp->ki_ruid),
thr_buf,
pp->ki_pri.pri_level - PZERO,
format_nice(pp),
format_k(PROCSIZE(pp)),
format_k(pagetok(pp->ki_rssize)),
swaplength, swaplength, swap_buf,
ps.swap ? TOP_SWAP_LEN : 0, ps.swap ? TOP_SWAP_LEN : 0, swap_buf,
status,
cpu,
format_time(cputime),

View File

@ -78,7 +78,7 @@ struct process_select
/* routines defined by the machine dependent module */
const char *format_header(const char *uname_field);
char *format_header(const char *uname_field);
char *format_next_process(void* handle, char *(*get_userid)(int),
int flags);
void toggle_pcpustats(void);

View File

@ -268,10 +268,8 @@ format_time(long seconds)
/*
* format_k(amt) - format a kilobyte memory value, returning a string
* suitable for display. Returns a pointer to a static
* area that changes each call. "amt" is converted to a
* string with a trailing "K". If "amt" is 10000 or greater,
* then it is formatted as megabytes (rounded) with a
* trailing "M".
* area that changes each call. "amt" is converted to a fixed
* size humanize_number call
*/
/*
@ -299,7 +297,7 @@ format_k(int64_t amt)
ret = retarray[index];
index = (index + 1) % NUM_STRINGS;
humanize_number(ret, 6, amt * 1024, "", HN_AUTOSCALE, HN_NOSPACE);
humanize_number(ret, 5, amt * 1024, "", HN_AUTOSCALE, HN_NOSPACE);
return (ret);
}