summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2025-08-06 00:05:44 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2025-08-06 00:05:44 +0200
commit1bd8d714ca1889558b26ab8f29a0f199ffdd2bd9 (patch)
treefe09a1dee81f5e44e008181014cc1cc442759cd2
parent23639388838448bb1968de70e84005904b316b93 (diff)
top: disentangle printing logic
function old new delta print_line_buf - 78 +78 print_line_bold - 50 +50 top_main 1043 1091 +48 handle_input 708 714 +6 do_stats 186 192 +6 .rodata 115543 115526 -17 display_topmem_process_list 748 523 -225 display_process_list 1432 1186 -246 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 3/3 up/down: 188/-488) Total: -300 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--procps/top.c180
1 files changed, 97 insertions, 83 deletions
diff --git a/procps/top.c b/procps/top.c
index 1f1c82b5a..bff9f7c4f 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -166,12 +166,14 @@ struct globals {
top_status_t *top;
int ntop;
smallint inverted;
+ smallint not_first_line;
#if ENABLE_FEATURE_TOPMEM
smallint sort_field;
#endif
#if ENABLE_FEATURE_TOP_SMP_CPU
smallint smp_cpu_info; /* one/many cpu info lines? */
#endif
+ int lines_remaining;
unsigned lines; /* screen height */
unsigned scr_width; /* width, clamped <= LINE_BUF_SIZE-2 */
#if ENABLE_FEATURE_TOP_INTERACTIVE
@@ -218,7 +220,6 @@ struct globals {
#define cpu_prev_jif (G.cpu_prev_jif )
#define num_cpus (G.num_cpus )
#define total_pcpu (G.total_pcpu )
-#define line_buf (G.line_buf )
#define INIT_G() do { \
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \
@@ -289,9 +290,9 @@ static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
#endif
int ret;
- if (!fgets(line_buf, LINE_BUF_SIZE, fp) || line_buf[0] != 'c' /* not "cpu" */)
+ if (!fgets(G.line_buf, LINE_BUF_SIZE, fp) || G.line_buf[0] != 'c' /* not "cpu" */)
return 0;
- ret = sscanf(line_buf, fmt,
+ ret = sscanf(G.line_buf, fmt,
&p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
&p_jif->iowait, &p_jif->irq, &p_jif->softirq,
&p_jif->steal);
@@ -413,6 +414,38 @@ static void do_stats(void)
#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
+static void print_line_buf(void)
+{
+ const char *fmt;
+
+ G.lines_remaining--;
+ fmt = OPT_BATCH_MODE ? "\n""%.*s" : "\n""%.*s"CLREOL;
+ if (!G.not_first_line) {
+ G.not_first_line = 1;
+ /* Go to top */
+ fmt = OPT_BATCH_MODE ? "%.*s" : HOME"%.*s"CLREOL;
+ }
+ printf(fmt, G.scr_width - 1, G.line_buf);
+}
+
+static void print_line_bold(void)
+{
+ G.lines_remaining--;
+//we never print first line in bold
+// if (!G.not_first_line) {
+// printf(OPT_BATCH_MODE ? "%.*s" : HOME"%.*s"CLREOL, G.scr_width - 1, G.line_buf);
+// G.not_first_line = 1;
+// } else {
+ printf(OPT_BATCH_MODE ? "\n""%.*s" : "\n"REVERSE"%.*s"NORMAL CLREOL, G.scr_width - 1, G.line_buf);
+// }
+}
+
+static void print_end(void)
+{
+ fputs_stdout(OPT_BATCH_MODE ? "\n" : CLREOS"\r");
+ G.not_first_line = 0; /* next print will be "first line" (will clear the screen) */
+}
+
#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS
/* formats 7 char string (8 with terminating NUL) */
static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total)
@@ -439,7 +472,7 @@ static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total)
#endif
#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
-static void display_cpus(char *scrbuf, int *lines_rem_p)
+static void display_cpus(void)
{
/*
* xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100%
@@ -475,8 +508,8 @@ static void display_cpus(char *scrbuf, int *lines_rem_p)
# else
/* Loop thru CPU(s) */
n_cpu_lines = smp_cpu_info ? num_cpus : 1;
- if (n_cpu_lines > *lines_rem_p)
- n_cpu_lines = *lines_rem_p;
+ if (n_cpu_lines > G.lines_remaining)
+ n_cpu_lines = G.lines_remaining;
for (i = 0; i < n_cpu_lines; i++) {
p_jif = &cpu_jif[i];
@@ -494,7 +527,7 @@ static void display_cpus(char *scrbuf, int *lines_rem_p)
CALC_STAT(softirq);
/*CALC_STAT(steal);*/
- snprintf(scrbuf, G.scr_width,
+ sprintf(G.line_buf,
/* Barely fits in 79 chars when in "decimals" mode. */
# if ENABLE_FEATURE_TOP_SMP_CPU
"CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq",
@@ -507,16 +540,15 @@ static void display_cpus(char *scrbuf, int *lines_rem_p)
/*, SHOW_STAT(steal) - what is this 'steal' thing? */
/* I doubt anyone wants to know it */
);
- printf(OPT_BATCH_MODE ? "%s\n" : "%s"CLREOL"\n", scrbuf);
+ print_line_buf();
}
}
# undef SHOW_STAT
# undef CALC_STAT
# undef FMT
- *lines_rem_p -= i;
}
#else /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */
-# define display_cpus(scrbuf, lines_rem) ((void)0)
+# define display_cpus() ((void)0)
#endif
enum {
@@ -570,51 +602,46 @@ static void parse_meminfo(unsigned long meminfo[MI_MAX])
fclose(f);
}
-static unsigned long display_header(int *lines_rem_p)
+static unsigned long display_header(void)
{
- char scrbuf[100]; /* [80] was a bit too low on 8Gb ram box */
char *buf;
- unsigned width;
unsigned long meminfo[MI_MAX];
parse_meminfo(meminfo);
/* Output memory info */
- width = (G.scr_width > sizeof(scrbuf)) ? sizeof(scrbuf) : G.scr_width;
- snprintf(scrbuf, width,
+ sprintf(G.line_buf,
"Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE],
meminfo[MI_MEMFREE],
meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM],
meminfo[MI_BUFFERS],
meminfo[MI_CACHED]);
- /* Go to top & clear to the end of screen */
- printf(OPT_BATCH_MODE ? "%s\n" : HOME"%s"CLREOL"\n", scrbuf);
- (*lines_rem_p)--;
+ print_line_buf();
/* Display CPU time split as percentage of total time.
* This displays either a cumulative line or one line per CPU.
*/
- display_cpus(scrbuf, lines_rem_p);
+ display_cpus();
/* Read load average as a string */
- buf = stpcpy(scrbuf, "Load average: ");
- open_read_close("loadavg", buf, sizeof(scrbuf) - sizeof("Load average: "));
+ buf = stpcpy(G.line_buf, "Load average: ");
+ open_read_close("loadavg", buf, sizeof(G.line_buf) - sizeof("Load average: "));
+ G.line_buf[sizeof(G.line_buf) - 1] = '\0'; /* paranoia */
strchrnul(buf, '\n')[0] = '\0';
- printf(OPT_BATCH_MODE ? "%.*s\n" : "%.*s"CLREOL"\n", width - 1, scrbuf);
- (*lines_rem_p)--;
+ print_line_buf();
return meminfo[MI_MEMTOTAL];
}
-static NOINLINE void display_process_list(int lines_rem)
+static NOINLINE void display_process_list(void)
{
enum {
BITS_PER_INT = sizeof(int) * 8
};
top_status_t *s;
- unsigned long total_memory = display_header(&lines_rem); /* or use total_memsize? */
+ unsigned long total_memory = display_header();
/* xxx_shift and xxx_scale variables allow us to replace
* expensive divides with multiply and shift */
unsigned pmem_shift, pmem_scale, pmem_half;
@@ -626,7 +653,7 @@ static NOINLINE void display_process_list(int lines_rem)
#if ENABLE_FEATURE_TOP_DECIMALS
# define UPSCALE 1000
-typedef struct { unsigned quot, rem; } bb_div_t;
+ typedef struct { unsigned quot, rem; } bb_div_t;
/* Used to have "div_t name = div((val), 10)" here
* (IOW: intended to use libc-compatible way to divide and use
* both result and remainder, but musl does not inline div()...)
@@ -644,13 +671,11 @@ typedef struct { unsigned quot, rem; } bb_div_t;
# define FMT "%4u%%"
#endif
- /* what info of the processes is shown */
- printf(OPT_BATCH_MODE ? "%.*s" : REVERSE"%.*s"NORMAL CLREOL, G.scr_width - 1,
- " PID PPID USER STAT RSS %RSS"
+ strcpy(G.line_buf, " PID PPID USER STAT RSS %RSS"
IF_FEATURE_TOP_SMP_PROCESS(" CPU")
IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU")
" COMMAND");
- lines_rem--;
+ print_line_bold();
/* %RSS = s->memsize / MemTotal * 100%
* Calculate this with multiply and shift. Example:
@@ -702,12 +727,12 @@ typedef struct { unsigned quot, rem; } bb_div_t;
pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2);
/* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
#endif
- if (lines_rem > ntop - G_scroll_ofs)
- lines_rem = ntop - G_scroll_ofs;
+ if (G.lines_remaining > ntop - G_scroll_ofs)
+ G.lines_remaining = ntop - G_scroll_ofs;
/* Ok, all preliminary data is ready, go through the list */
s = top + G_scroll_ofs;
- while (--lines_rem >= 0) {
+ while (G.lines_remaining > 0) {
int n;
char *ppu;
char ppubuf[sizeof(int)*3 * 2 + 12];
@@ -753,7 +778,7 @@ typedef struct { unsigned quot, rem; } bb_div_t;
ppu[6+6+8] = '\0'; /* truncate USER */
}
shortened:
- col = snprintf(line_buf, G.scr_width,
+ col = sprintf(G.line_buf,
"%s %s %.5s" FMT
IF_FEATURE_TOP_SMP_PROCESS(" %3d")
IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT)
@@ -765,14 +790,13 @@ typedef struct { unsigned quot, rem; } bb_div_t;
IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu))
);
if ((int)(G.scr_width - col) > 1)
- read_cmdline(line_buf + col, G.scr_width - col, s->pid, s->comm);
- printf(OPT_BATCH_MODE ? "\n""%s" : "\n""%s"CLREOL, line_buf);
+ read_cmdline(G.line_buf + col, G.scr_width - col, s->pid, s->comm);
+ print_line_buf();
/* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */
s++;
}
/* printf(" %d", hist_iterations); */
- fputs_stdout(OPT_BATCH_MODE ? "\n" : CLREOS"\r");
}
#undef UPSCALE
#undef SHOW_STAT
@@ -844,36 +868,34 @@ static int topmem_sort(char *a, char *b)
}
/* display header info (meminfo / loadavg) */
-static void display_topmem_header(int *lines_rem_p)
+static void display_topmem_header(void)
{
unsigned long meminfo[MI_MAX];
parse_meminfo(meminfo);
- snprintf(line_buf, LINE_BUF_SIZE,
+ sprintf(G.line_buf,
"Mem total:%lu anon:%lu map:%lu free:%lu",
meminfo[MI_MEMTOTAL],
meminfo[MI_ANONPAGES],
meminfo[MI_MAPPED],
meminfo[MI_MEMFREE]);
- printf(OPT_BATCH_MODE ? "%.*s\n" : HOME"%.*s"CLREOL"\n", G.scr_width - 1, line_buf);
+ print_line_buf();
- snprintf(line_buf, LINE_BUF_SIZE,
+ sprintf(G.line_buf,
" slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu",
meminfo[MI_SLAB],
meminfo[MI_BUFFERS],
meminfo[MI_CACHED],
meminfo[MI_DIRTY],
meminfo[MI_WRITEBACK]);
- printf(OPT_BATCH_MODE ? "%.*s\n" : "%.*s"CLREOL"\n", G.scr_width - 1, line_buf);
+ print_line_buf();
- snprintf(line_buf, LINE_BUF_SIZE,
+ sprintf(G.line_buf,
"Swap total:%lu free:%lu", // TODO: % used?
meminfo[MI_SWAPTOTAL],
meminfo[MI_SWAPFREE]);
- printf(OPT_BATCH_MODE ? "%.*s\n" : "%.*s"CLREOL"\n", G.scr_width - 1, line_buf);
-
- (*lines_rem_p) -= 3;
+ print_line_buf();
}
/* see http://en.wikipedia.org/wiki/Tera */
@@ -886,67 +908,57 @@ static void ulltoa4_and_space(unsigned long long ul, char buf[5])
smart_ulltoa4(ul, buf, " mgtpezy")[0] = ' ';
}
-static NOINLINE void display_topmem_process_list(int lines_rem)
+static NOINLINE void display_topmem_process_list(void)
{
#define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK"
#define MIN_WIDTH sizeof(HDR_STR)
const topmem_status_t *s = topmem + G_scroll_ofs;
char *cp, ch;
- display_topmem_header(&lines_rem);
+ display_topmem_header();
- strcpy(line_buf, HDR_STR " COMMAND");
+ strcpy(G.line_buf, HDR_STR " COMMAND");
/* Mark the ^FIELD^ we sort by */
- cp = &line_buf[5 + sort_field * 6];
+ cp = &G.line_buf[5 + sort_field * 6];
ch = "^_"[inverted];
cp[6] = ch;
do *cp++ = ch; while (*cp == ' ');
+ print_line_bold();
- printf(OPT_BATCH_MODE ? "%.*s" : REVERSE"%.*s"NORMAL CLREOL, G.scr_width - 1, line_buf);
- lines_rem--;
-
- if (lines_rem > ntop - G_scroll_ofs)
- lines_rem = ntop - G_scroll_ofs;
- while (--lines_rem >= 0) {
+ if (G.lines_remaining > ntop - G_scroll_ofs)
+ G.lines_remaining = ntop - G_scroll_ofs;
+ while (G.lines_remaining > 0) {
/* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */
- int n = sprintf(line_buf, "%5u ", s->pid);
+ int n = sprintf(G.line_buf, "%5u ", s->pid);
if (n > 7) {
/* PID is 7 chars long (up to 4194304) */
- ulltoa4_and_space(s->vsz , &line_buf[8]);
- ulltoa4_and_space(s->vszrw, &line_buf[8+5]);
+ ulltoa4_and_space(s->vsz , &G.line_buf[8]);
+ ulltoa4_and_space(s->vszrw, &G.line_buf[8+5]);
/* the next field (RSS) starts at 8+10 = 3*6 */
} else {
if (n == 7) /* PID is 6 chars long */
- ulltoa4_and_space(s->vsz, &line_buf[7]);
+ ulltoa4_and_space(s->vsz, &G.line_buf[7]);
/* the next field (VSZRW) starts at 7+5 = 2*6 */
else /* PID is 5 chars or less */
- ulltoa5_and_space(s->vsz, &line_buf[6]);
- ulltoa5_and_space(s->vszrw, &line_buf[2*6]);
+ ulltoa5_and_space(s->vsz, &G.line_buf[6]);
+ ulltoa5_and_space(s->vszrw, &G.line_buf[2*6]);
}
- ulltoa5_and_space(s->rss , &line_buf[3*6]);
- ulltoa5_and_space(s->rss_sh , &line_buf[4*6]);
- ulltoa5_and_space(s->dirty , &line_buf[5*6]);
- ulltoa5_and_space(s->dirty_sh, &line_buf[6*6]);
- ulltoa5_and_space(s->stack , &line_buf[7*6]);
- line_buf[8*6] = '\0';
+ ulltoa5_and_space(s->rss , &G.line_buf[3*6]);
+ ulltoa5_and_space(s->rss_sh , &G.line_buf[4*6]);
+ ulltoa5_and_space(s->dirty , &G.line_buf[5*6]);
+ ulltoa5_and_space(s->dirty_sh, &G.line_buf[6*6]);
+ ulltoa5_and_space(s->stack , &G.line_buf[7*6]);
+ G.line_buf[8*6] = '\0';
if ((int)(G.scr_width - MIN_WIDTH) > 1)
- read_cmdline(&line_buf[8*6], G.scr_width - MIN_WIDTH, s->pid, s->comm);
- printf(OPT_BATCH_MODE ? "\n""%.*s" : "\n""%.*s"CLREOL, G.scr_width, line_buf);
+ read_cmdline(&G.line_buf[8*6], G.scr_width - MIN_WIDTH, s->pid, s->comm);
+ print_line_buf();
s++;
}
- fputs_stdout(OPT_BATCH_MODE ? "\n" : CLREOS"\r");
#undef HDR_STR
#undef MIN_WIDTH
}
-#else
-//void display_topmem_process_list(int lines_rem);
-//int topmem_sort(char *a, char *b);
-#endif /* TOPMEM */
-
-/*
- * end TOPMEM support
- */
+#endif /* end TOPMEM support */
enum {
TOP_MASK = 0
@@ -1228,7 +1240,6 @@ int top_main(int argc UNUSED_PARAM, char **argv)
}
#endif
- /* change to /proc */
xchdir("/proc");
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
@@ -1340,14 +1351,16 @@ int top_main(int argc UNUSED_PARAM, char **argv)
}
#endif
IF_FEATURE_TOP_INTERACTIVE(redraw:)
+ G.lines_remaining = G.lines;
IF_FEATURE_TOPMEM(if (scan_mask != TOPMEM_MASK)) {
- display_process_list(G.lines);
+ display_process_list();
}
#if ENABLE_FEATURE_TOPMEM
else { /* TOPMEM */
- display_topmem_process_list(G.lines);
+ display_topmem_process_list();
}
#endif
+ print_end();
fflush_all();
if (iterations >= 0 && !--iterations)
break;
@@ -1369,7 +1382,8 @@ int top_main(int argc UNUSED_PARAM, char **argv)
#endif
} /* end of "while (not Q)" */
- bb_putchar('\n');
+ if (!OPT_BATCH_MODE)
+ bb_putchar('\n');
#if ENABLE_FEATURE_TOP_INTERACTIVE
reset_term();
#endif