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:
committed by
Siarzhuk Zharski
parent
e056d32027
commit
a6e7154312
+84
-58
@@ -45,6 +45,14 @@ typedef struct {
|
|||||||
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(×);
|
grow(×);
|
||||||
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(×);
|
grow(×);
|
||||||
@@ -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;
|
||||||
@@ -232,11 +260,8 @@ compare(
|
|||||||
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;
|
||||||
|
|
||||||
|
if (columns <= 80)
|
||||||
t.name[16] = 0;
|
t.name[16] = 0;
|
||||||
total = (times.thread_times[i].user_time +
|
else
|
||||||
times.thread_times[i].kernel_time);
|
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,7 +303,7 @@ 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),
|
||||||
@@ -293,18 +323,14 @@ compare(
|
|||||||
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, ×, old_busy, *busy_wait_time,
|
compare(old, ×, old_busy, *busy_wait_time,
|
||||||
@@ -384,6 +400,7 @@ gather(
|
|||||||
return (times);
|
return (times);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* print usage message and exit
|
* print usage message and exit
|
||||||
*/
|
*/
|
||||||
@@ -401,6 +418,7 @@ usage(const char *myname)
|
|||||||
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,8 +461,11 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,6 +476,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGWINCH, winch_handler);
|
signal(SIGWINCH, winch_handler);
|
||||||
|
signal(SIGINT, sigint_handler);
|
||||||
|
|
||||||
lastMeasure = system_time();
|
lastMeasure = system_time();
|
||||||
if (iters < 0) {
|
if (iters < 0) {
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user