top: use alternate screen buffer for info output

* output teams information into alternate screen output - like in
  other operating systems - prevent Terminal history from trashing with
  multiple screenshots of displayed information;
* Fixes #9509.

- GCI 2013
This commit is contained in:
Freeman Lou
2013-12-01 22:54:44 +01:00
committed by Siarzhuk Zharski
parent e056d32027
commit a6e7154312
+111 -85
View File
@@ -23,7 +23,7 @@ static const char IDLE_NAME[] = "idle thread ";
static bigtime_t lastMeasure = 0; static bigtime_t lastMeasure = 0;
/* /*
* Keeps track of a single thread's times * Keeps track of a single thread's times
*/ */
typedef struct { typedef struct {
thread_id thid; thread_id thid;
@@ -44,7 +44,15 @@ typedef struct {
#define FREELIST_SIZE 3 #define FREELIST_SIZE 3
static thread_time_list_t freelist[FREELIST_SIZE]; static thread_time_list_t freelist[FREELIST_SIZE];
static char *clear_string; /* output string for clearing the screen */ static char *clear_string; /*output string for clearing the screen */
static char *enter_ca_mode; /* output string for switching screen buffer */
static char *exit_ca_mode; /* output string for releasing screen buffer */
static char *cursor_home; /* Places cursor back to (1,1) */
static char *restore_cursor;
static char *save_cursor;
static char buf[2048];
static char *entries = &buf[0];
static int columns; /* Columns on screen */
static int rows; /* how many rows on the screen */ static int rows; /* how many rows on the screen */
static int screen_size_changed = 0; /* tells to refresh the screen size */ static int screen_size_changed = 0; /* tells to refresh the screen size */
static int cpus; /* how many cpus we are runing on */ static int cpus; /* how many cpus we are runing on */
@@ -57,6 +65,17 @@ winch_handler(int notused)
screen_size_changed = 1; screen_size_changed = 1;
} }
/* SIGINT handler */
static void
sigint_handler()
{
printf(exit_ca_mode);
printf(restore_cursor);
exit(1);
}
/* /*
* Grow the list to add just one more entry * Grow the list to add just one more entry
*/ */
@@ -67,8 +86,7 @@ grow(thread_time_list_t *times)
if (times->nthreads == times->maxthreads) { if (times->nthreads == times->maxthreads) {
times->thread_times = realloc(times->thread_times, times->thread_times = realloc(times->thread_times,
(sizeof(times->thread_times[0]) * (sizeof(times->thread_times[0]) * (times->nthreads + 1)));
(times->nthreads + 1)));
times->maxthreads = times->nthreads + 1; times->maxthreads = times->nthreads + 1;
} }
i = times->nthreads; i = times->nthreads;
@@ -78,6 +96,24 @@ grow(thread_time_list_t *times)
times->nthreads++; times->nthreads++;
} }
static void
init_term()
{
tgetent(buf, getenv("TERM"));
exit_ca_mode = tgetstr("te", &entries);
enter_ca_mode = tgetstr("ti", &entries);
cursor_home = tgetstr("ho", &entries);
clear_string = tgetstr("cl", &entries);
restore_cursor = tgetstr("rc", &entries);
save_cursor = tgetstr("sc", &entries);
printf(save_cursor);
printf(enter_ca_mode);
printf(clear_string);
}
static void static void
init_times(thread_time_list_t *times) init_times(thread_time_list_t *times)
{ {
@@ -93,6 +129,7 @@ init_times(thread_time_list_t *times)
fprintf(stderr, "This can't happen\n"); fprintf(stderr, "This can't happen\n");
} }
static void static void
free_times(thread_time_list_t *times) free_times(thread_time_list_t *times)
{ {
@@ -108,6 +145,7 @@ free_times(thread_time_list_t *times)
fprintf(stderr, "This can't happen\n"); fprintf(stderr, "This can't happen\n");
} }
/* /*
* Compare two thread snapshots (for qsort) * Compare two thread snapshots (for qsort)
*/ */
@@ -117,10 +155,11 @@ comparetime(const void *a, const void *b)
thread_times_t *ta = (thread_times_t *)a; thread_times_t *ta = (thread_times_t *)a;
thread_times_t *tb = (thread_times_t *)b; thread_times_t *tb = (thread_times_t *)b;
return ((tb->user_time + tb->kernel_time) - return ((tb->user_time + tb->kernel_time)
(ta->user_time + ta->kernel_time)); - (ta->user_time + ta->kernel_time));
} }
/* /*
* Calculate the cpu percentage used by a given thread * Calculate the cpu percentage used by a given thread
* Remember: for multiple CPUs, multiply the interval by # cpus * Remember: for multiple CPUs, multiply the interval by # cpus
@@ -132,17 +171,6 @@ cpu_perc(bigtime_t spent, bigtime_t interval)
return ((100.0 * spent) / (cpus * interval)); return ((100.0 * spent) / (cpus * interval));
} }
/*
* Clear the screen
*/
static void
clear(void)
{
if (clear_string) {
printf(clear_string);
fflush(stdout);
}
}
/* /*
* Compare an old snapshot with the new one * Compare an old snapshot with the new one
@@ -195,20 +223,20 @@ compare(
continue; continue;
} }
newthread = 0; newthread = 0;
oldtime = (old->thread_times[i].user_time + oldtime = (old->thread_times[i].user_time
old->thread_times[i].kernel_time); + old->thread_times[i].kernel_time);
newtime = (new->thread_times[j].user_time + newtime = (new->thread_times[j].user_time
new->thread_times[j].kernel_time); + new->thread_times[j].kernel_time);
if (oldtime == newtime) { if (oldtime == newtime) {
ignore = 1; ignore = 1;
break; break;
} }
grow(&times); grow(&times);
times.thread_times[k].thid = new->thread_times[j].thid; times.thread_times[k].thid = new->thread_times[j].thid;
times.thread_times[k].user_time = (new->thread_times[j].user_time - times.thread_times[k].user_time = (new->thread_times[j].user_time
old->thread_times[i].user_time); - old->thread_times[i].user_time);
times.thread_times[k].kernel_time = (new->thread_times[j].kernel_time - times.thread_times[k].kernel_time = (new->thread_times[j].kernel_time
old->thread_times[i].kernel_time); - old->thread_times[i].kernel_time);
} }
if (newthread) { if (newthread) {
grow(&times); grow(&times);
@@ -217,8 +245,8 @@ compare(
times.thread_times[k].kernel_time = new->thread_times[j].kernel_time; times.thread_times[k].kernel_time = new->thread_times[j].kernel_time;
} }
if (!ignore) { if (!ignore) {
total = (times.thread_times[k].user_time + total = (times.thread_times[k].user_time
times.thread_times[k].kernel_time); + times.thread_times[k].kernel_time);
gtotal += total; gtotal += total;
utotal += times.thread_times[k].user_time; utotal += times.thread_times[k].user_time;
ktotal += times.thread_times[k].kernel_time; ktotal += times.thread_times[k].kernel_time;
@@ -229,14 +257,11 @@ compare(
/* /*
* Sort what we found and print * Sort what we found and print
*/ */
qsort(times.thread_times, times.nthreads, qsort(times.thread_times, times.nthreads,
sizeof(times.thread_times[0]), comparetime); sizeof(times.thread_times[0]), comparetime);
if (refresh) { printf("%6s %7s %7s %7s %4s %16s %-16s \n", "THID", "TOTAL", "USER", "KERNEL",
clear(); "%CPU", "TEAM NAME", "THREAD NAME");
}
printf("%6s %7s %7s %7s %4s %16s %16s\n", "thid", "total", "user", "kernel",
"%cpu", "team name", "thread name");
linecount = 1; linecount = 1;
idletime = new_busy - old_busy; idletime = new_busy - old_busy;
gtotal = 0; gtotal = 0;
@@ -261,9 +286,14 @@ compare(
} }
tm.args[16] = 0; tm.args[16] = 0;
t.name[16] = 0;
total = (times.thread_times[i].user_time + if (columns <= 80)
times.thread_times[i].kernel_time); t.name[16] = 0;
else
t.name[columns - 64] = 0;
total = (times.thread_times[i].user_time
+ times.thread_times[i].kernel_time);
if (ignore) { if (ignore) {
idletime += total; idletime += total;
} else { } else {
@@ -273,38 +303,34 @@ compare(
} }
if (!ignore && (!refresh || (linecount < (rows - 1)))) { if (!ignore && (!refresh || (linecount < (rows - 1)))) {
printf("%6ld %7.2f %7.2f %7.2f %4.1f %16s %16s\n", printf("%6ld %7.2f %7.2f %7.2f %4.1f %16s %s \n",
times.thread_times[i].thid, times.thread_times[i].thid,
total / 1000.0, total / 1000.0,
(double)(times.thread_times[i].user_time / 1000), (double)(times.thread_times[i].user_time / 1000),
(double)(times.thread_times[i].kernel_time / 1000), (double)(times.thread_times[i].kernel_time / 1000),
cpu_perc(total, uinterval), cpu_perc(total, uinterval),
tm.args, tm.args,
t.name); t.name);
linecount++; linecount++;
} }
} }
free_times(&times); free_times(&times);
printf("------ %7.2f %7.2f %7.2f %4.1f%% TOTAL (%4.1f%% idle time, %4.1f%% unknown)", printf("------ %7.2f %7.2f %7.2f %4.1f%% TOTAL (%4.1f%% idle time, %4.1f%% unknown)",
(double) (gtotal / 1000), (double) (gtotal / 1000),
(double) (utotal / 1000), (double) (utotal / 1000),
(double) (ktotal / 1000), (double) (ktotal / 1000),
cpu_perc(gtotal, uinterval), cpu_perc(gtotal, uinterval),
cpu_perc(idletime, uinterval), cpu_perc(idletime, uinterval),
cpu_perc(cpus * uinterval - (gtotal + idletime), uinterval)); cpu_perc(cpus * uinterval - (gtotal + idletime), uinterval));
fflush(stdout); fflush(stdout);
if (!refresh) { printf(clear_string);
printf("\n\n"); printf(cursor_home);
}
} }
static int static int
setup_term(bool onlyRows) adjust_term(bool onlyRows)
{ {
char *term;
char *str;
char buf[2048];
char *entries;
struct winsize ws; struct winsize ws;
if (ioctl(1, TIOCGWINSZ, &ws) < 0) { if (ioctl(1, TIOCGWINSZ, &ws) < 0) {
@@ -313,25 +339,15 @@ setup_term(bool onlyRows)
if (ws.ws_row <= 0) { if (ws.ws_row <= 0) {
return (0); return (0);
} }
columns = ws.ws_col;
rows = ws.ws_row; rows = ws.ws_row;
if (onlyRows) if (onlyRows)
return 1; return 1;
term = getenv("TERM");
if (term == NULL) {
return (0);
}
if (tgetent(buf, term) <= 0) {
return (0);
}
entries = &buf[0];
str = tgetstr("cl", &entries);
if (str == NULL) {
return (0);
}
clear_string = strdup(str);
return (1); return (1);
} }
/* /*
* Gather up thread data for uinterval microseconds * Gather up thread data for uinterval microseconds
*/ */
@@ -374,7 +390,7 @@ gather(
} }
if (old != NULL) { if (old != NULL) {
if (screen_size_changed) { if (screen_size_changed) {
setup_term(true); adjust_term(true);
screen_size_changed = 0; screen_size_changed = 0;
} }
compare(old, &times, old_busy, *busy_wait_time, compare(old, &times, old_busy, *busy_wait_time,
@@ -384,6 +400,7 @@ gather(
return (times); return (times);
} }
/* /*
* print usage message and exit * print usage message and exit
*/ */
@@ -391,16 +408,17 @@ static void
usage(const char *myname) usage(const char *myname)
{ {
fprintf(stderr, "usage: %s [-d] [-i interval] [-n ntimes]\n", myname); fprintf(stderr, "usage: %s [-d] [-i interval] [-n ntimes]\n", myname);
fprintf(stderr, fprintf(stderr,
" -d, do not clear the screen between displays\n"); " -d, do not clear the screen between displays\n");
fprintf(stderr, fprintf(stderr,
" -i interval, wait `interval' seconds before displaying\n"); " -i interval, wait `interval' seconds before displaying\n");
fprintf(stderr, fprintf(stderr,
" -n ntimes, display `ntimes' times before exiting\n"); " -n ntimes, display `ntimes' times before exiting\n");
fprintf(stderr, "Default is clear screen, interval=5, ntimes=infinite\n"); fprintf(stderr, "Default is clear screen, interval=5, ntimes=infinite\n");
exit(1); exit(1);
} }
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@@ -411,7 +429,7 @@ main(int argc, char **argv)
int refresh = 1; int refresh = 1;
system_info sysinfo; system_info sysinfo;
//bigtime_t now; //bigtime_t now;
bigtime_t then; //bigtime_t then;
bigtime_t uinterval; bigtime_t uinterval;
bigtime_t elapsed; bigtime_t elapsed;
bigtime_t busy; bigtime_t busy;
@@ -443,19 +461,23 @@ main(int argc, char **argv)
if (argc) { if (argc) {
usage(myname); usage(myname);
} }
init_term();
if (refresh) { if (refresh) {
if (!setup_term(false)) { if (!adjust_term(false)) {
refresh = 0; refresh = 0;
} }
} }
if (iters >= 0) { if (iters >= 0) {
printf("Starting: %d interval%s of %d second%s each\n", iters, printf("Starting: %d interval%s of %d second%s each\n", iters,
(iters == 1) ? "" : "s", interval, (iters == 1) ? "" : "s", interval,
(interval == 1) ? "" : "s"); (interval == 1) ? "" : "s");
} }
signal(SIGWINCH, winch_handler); signal(SIGWINCH, winch_handler);
signal(SIGINT, sigint_handler);
lastMeasure = system_time(); lastMeasure = system_time();
if (iters < 0) { if (iters < 0) {
// You will only have to wait half a second for the first iteration. // You will only have to wait half a second for the first iteration.
@@ -464,7 +486,7 @@ main(int argc, char **argv)
elapsed = system_time() - lastMeasure; elapsed = system_time() - lastMeasure;
if (elapsed < uinterval) if (elapsed < uinterval)
snooze(uinterval - elapsed); snooze(uinterval - elapsed);
then = system_time(); // then = system_time();
baseline = gather(&baseline, &busy, refresh); baseline = gather(&baseline, &busy, refresh);
} else } else
@@ -477,5 +499,9 @@ main(int argc, char **argv)
snooze(uinterval - elapsed); snooze(uinterval - elapsed);
baseline = gather(&baseline, &busy, refresh); baseline = gather(&baseline, &busy, refresh);
} }
printf(exit_ca_mode);
printf(restore_cursor);
exit(0); exit(0);
} }