2 * Copyright (c) 2010 Stanislav Kozina
3 * Copyright (c) 2010 Martin Decky
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include <io/console.h>
51 static usec_t timeleft
= 0;
53 console_ctrl_t
*console
;
55 static sysarg_t warning_col
= 0;
56 static sysarg_t warning_row
= 0;
57 static usec_t warning_timeleft
= 0;
58 static char *warning_text
= NULL
;
60 static void screen_style_normal(void)
62 console_flush(console
);
63 console_set_style(console
, STYLE_NORMAL
);
66 static void screen_style_inverted(void)
68 console_flush(console
);
69 console_set_style(console
, STYLE_INVERTED
);
72 static void screen_style_emphasis(void)
74 console_flush(console
);
75 console_set_style(console
, STYLE_EMPHASIS
);
78 static void screen_moveto(sysarg_t col
, sysarg_t row
)
80 console_flush(console
);
81 console_set_pos(console
, col
, row
);
84 static void screen_get_pos(sysarg_t
*col
, sysarg_t
*row
)
86 console_flush(console
);
87 console_get_pos(console
, col
, row
);
90 static void screen_get_size(sysarg_t
*col
, sysarg_t
*row
)
92 console_flush(console
);
93 console_get_size(console
, col
, row
);
96 static void screen_restart(bool clear
)
98 screen_style_normal();
101 console_flush(console
);
102 console_clear(console
);
108 static void screen_newline(void)
112 screen_get_size(&cols
, &rows
);
116 screen_get_pos(&c
, &r
);
119 for (i
= c
+ 1; i
< cols
; i
++)
126 void screen_init(void)
128 console
= console_init(stdin
, stdout
);
130 console_flush(console
);
131 console_cursor_visibility(console
, false);
133 screen_restart(true);
136 void screen_done(void)
141 screen_restart(true);
143 console_flush(console
);
144 console_cursor_visibility(console
, true);
147 static void print_percent(fixed_float ffloat
, unsigned int precision
)
149 printf("%3" PRIu64
".", ffloat
.upper
/ ffloat
.lower
);
152 uint64_t rest
= (ffloat
.upper
% ffloat
.lower
) * 10;
153 for (i
= 0; i
< precision
; i
++) {
154 printf("%" PRIu64
, rest
/ ffloat
.lower
);
155 rest
= (rest
% ffloat
.lower
) * 10;
161 static void print_string(const char *str
)
165 screen_get_size(&cols
, &rows
);
169 screen_get_pos(&c
, &r
);
172 int pos
= cols
- c
- 1;
173 printf("%.*s", pos
, str
);
177 static inline void print_global_head(data_t
*data
)
179 printf("top - %02lld:%02lld:%02lld up "
180 "%" PRIun
" days, %02" PRIun
":%02" PRIun
":%02" PRIun
", "
182 data
->hours
, data
->minutes
, data
->seconds
,
183 data
->udays
, data
->uhours
, data
->uminutes
, data
->useconds
);
186 for (i
= 0; i
< data
->load_count
; i
++) {
188 stats_print_load_fragment(data
->load
[i
], 2);
194 static inline void print_task_summary(data_t
*data
)
196 printf("tasks: %zu total", data
->tasks_count
);
200 static inline void print_thread_summary(data_t
*data
)
206 size_t lingering
= 0;
211 for (i
= 0; i
< data
->threads_count
; i
++) {
214 switch (data
->threads
[i
].state
) {
236 printf("threads: %zu total, %zu running, %zu ready, "
237 "%zu sleeping, %zu lingering, %zu other, %zu invalid",
238 total
, running
, ready
, sleeping
, lingering
, other
, invalid
);
242 static inline void print_cpu_info(data_t
*data
)
245 for (i
= 0; i
< data
->cpus_count
; i
++) {
246 if (data
->cpus
[i
].active
) {
252 order_suffix(data
->cpus
[i
].busy_cycles
, &busy
, &busy_suffix
);
253 order_suffix(data
->cpus
[i
].idle_cycles
, &idle
, &idle_suffix
);
255 printf("cpu%u (%4" PRIu16
" MHz): busy cycles: "
256 "%" PRIu64
"%c, idle cycles: %" PRIu64
"%c",
257 data
->cpus
[i
].id
, data
->cpus
[i
].frequency_mhz
,
258 busy
, busy_suffix
, idle
, idle_suffix
);
259 fputs(", idle: ", stdout
);
260 print_percent(data
->cpus_perc
[i
].idle
, 2);
261 fputs(", busy: ", stdout
);
262 print_percent(data
->cpus_perc
[i
].busy
, 2);
264 printf("cpu%u inactive", data
->cpus
[i
].id
);
270 static inline void print_physmem_info(data_t
*data
)
276 const char *total_suffix
;
277 const char *unavail_suffix
;
278 const char *used_suffix
;
279 const char *free_suffix
;
281 bin_order_suffix(data
->physmem
->total
, &total
, &total_suffix
, false);
282 bin_order_suffix(data
->physmem
->unavail
, &unavail
, &unavail_suffix
, false);
283 bin_order_suffix(data
->physmem
->used
, &used
, &used_suffix
, false);
284 bin_order_suffix(data
->physmem
->free
, &free
, &free_suffix
, false);
286 printf("memory: %" PRIu64
"%s total, %" PRIu64
"%s unavail, %"
287 PRIu64
"%s used, %" PRIu64
"%s free", total
, total_suffix
,
288 unavail
, unavail_suffix
, used
, used_suffix
, free
, free_suffix
);
292 static inline void print_help_head(void)
294 screen_style_inverted();
297 screen_style_normal();
300 static inline void print_help(void)
304 screen_get_size(&cols
, &rows
);
308 printf("Operation modes:");
311 printf(" t .. tasks statistics");
314 printf(" i .. IPC statistics");
317 printf(" e .. exceptions statistics");
320 printf(" a .. toggle display of all/hot exceptions");
323 printf(" h .. toggle this help screen");
328 printf("Other keys:");
331 printf(" s .. choose column to sort by");
334 printf(" r .. toggle reversed sorting");
337 printf(" q .. quit");
342 screen_get_pos(&col
, &row
);
350 static inline void print_table_head(const table_t
*table
)
354 screen_get_size(&cols
, &rows
);
356 screen_style_inverted();
357 for (size_t i
= 0; i
< table
->num_columns
; i
++) {
358 const char *name
= table
->columns
[i
].name
;
359 int width
= table
->columns
[i
].width
;
366 screen_get_pos(&col
, &row
);
367 width
= cols
- col
- 1;
369 printf("[%-*.*s]", width
- 2, width
- 2, name
);
372 screen_style_normal();
375 static inline void print_table(const table_t
*table
)
379 screen_get_size(&cols
, &rows
);
383 screen_get_pos(&col
, &row
);
386 for (i
= 0; (i
< table
->num_fields
) && (row
< rows
); i
++) {
387 size_t column_index
= i
% table
->num_columns
;
388 int width
= table
->columns
[column_index
].width
;
389 field_t
*field
= &table
->fields
[i
];
394 if (column_index
!= 0) {
399 screen_get_pos(&col
, &row
);
400 width
= cols
- col
- 1;
403 switch (field
->type
) {
405 printf("%*s", width
, "");
408 printf("%*" PRIu64
, width
, field
->uint
);
410 case FIELD_UINT_SUFFIX_BIN
:
413 bin_order_suffix(val
, &val
, &psuffix
, true);
414 printf("%*" PRIu64
"%s", width
, val
, psuffix
);
416 case FIELD_UINT_SUFFIX_DEC
:
419 order_suffix(val
, &val
, &suffix
);
420 printf("%*" PRIu64
"%c", width
, val
, suffix
);
423 width
-= 5; /* nnn.% */
425 printf("%*s", width
- 2, "");
428 print_percent(field
->fixed
, width
);
431 printf("%-*.*s", width
, width
, field
->string
);
435 if (column_index
== table
->num_columns
- 1) {
447 static inline void print_sort(table_t
*table
)
451 screen_get_size(&cols
, &rows
);
455 screen_get_pos(&col
, &row
);
457 size_t num
= min(table
->num_columns
, rows
- row
);
458 for (size_t i
= 0; i
< num
; i
++) {
459 printf("%c - %s", table
->columns
[i
].key
, table
->columns
[i
].name
);
470 static inline void print_warning(void)
472 screen_get_pos(&warning_col
, &warning_row
);
473 if (warning_timeleft
> 0) {
474 screen_style_emphasis();
475 print_string(warning_text
);
476 screen_style_normal();
484 void print_data(data_t
*data
)
486 screen_restart(false);
487 print_global_head(data
);
488 print_task_summary(data
);
489 print_thread_summary(data
);
490 print_cpu_info(data
);
491 print_physmem_info(data
);
494 switch (screen_mode
) {
496 print_table_head(&data
->table
);
497 print_table(&data
->table
);
500 print_sort(&data
->table
);
507 console_flush(console
);
510 void show_warning(const char *fmt
, ...)
514 screen_get_size(&cols
, &rows
);
516 size_t warning_text_size
= 1 + cols
* sizeof(*warning_text
);
518 warning_text
= malloc(warning_text_size
);
524 vsnprintf(warning_text
, warning_text_size
, fmt
, args
);
527 warning_timeleft
= SEC2USEC(2);
529 screen_moveto(warning_col
, warning_row
);
531 console_flush(console
);
534 /** Get char with timeout
537 int tgetchar(sec_t sec
)
540 * Reset timeleft whenever it is not positive.
544 timeleft
= SEC2USEC(sec
);
547 * Wait to see if there is any input. If so, take it and
548 * update timeleft so that the next call to tgetchar()
549 * will not wait as long. If there is no input,
550 * make timeleft zero and return -1.
558 warning_timeleft
-= timeleft
;
559 if (!console_get_event_timeout(console
, &event
, &timeleft
)) {
563 warning_timeleft
+= timeleft
;
565 if (event
.type
== CEV_KEY
&& event
.ev
.key
.type
== KEY_PRESS
)