source: mainline/uspace/app/top/screen.c@ 1569a9b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1569a9b was 07b7c48, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Extend console library API to support different event types.

  • Property mode set to 100644
File size: 12.0 KB
RevLine 
[5c058d50]1/*
2 * Copyright (c) 2010 Stanislav Kozina
[dec16a2]3 * Copyright (c) 2010 Martin Decky
[5c058d50]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
17 *
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.
28 */
29
30/** @addtogroup top
31 * @brief Top utility.
32 * @{
33 */
34/**
35 * @file
36 */
37
38#include <stdio.h>
[2d37006]39#include <stdlib.h>
[5c058d50]40#include <io/console.h>
[9f1362d4]41#include <io/style.h>
[5c058d50]42#include <vfs/vfs.h>
[dec16a2]43#include <stdarg.h>
44#include <stats.h>
45#include <inttypes.h>
[b8d6783]46#include <macros.h>
[5c058d50]47#include "screen.h"
[79edc36]48#include "top.h"
[5c058d50]49
[79ae36dd]50#define USEC_COUNT 1000000
51
52static suseconds_t timeleft = 0;
53
54console_ctrl_t *console;
[8f56d93]55
[2d37006]56static sysarg_t warning_col = 0;
57static sysarg_t warning_row = 0;
58static suseconds_t warning_timeleft = 0;
59static char *warning_text = NULL;
60
[9f1362d4]61static void screen_style_normal(void)
62{
[79ae36dd]63 console_flush(console);
64 console_set_style(console, STYLE_NORMAL);
[9f1362d4]65}
[8f56d93]66
[9f1362d4]67static void screen_style_inverted(void)
[ee35ba0b]68{
[79ae36dd]69 console_flush(console);
70 console_set_style(console, STYLE_INVERTED);
[ee35ba0b]71}
72
[2d37006]73static void screen_style_emphasis(void)
74{
75 console_flush(console);
76 console_set_style(console, STYLE_EMPHASIS);
77}
78
[96b02eb9]79static void screen_moveto(sysarg_t col, sysarg_t row)
[5c058d50]80{
[79ae36dd]81 console_flush(console);
82 console_set_pos(console, col, row);
[5c058d50]83}
84
[96b02eb9]85static void screen_get_pos(sysarg_t *col, sysarg_t *row)
[5c058d50]86{
[79ae36dd]87 console_flush(console);
88 console_get_pos(console, col, row);
[5c058d50]89}
90
[96b02eb9]91static void screen_get_size(sysarg_t *col, sysarg_t *row)
[5c058d50]92{
[79ae36dd]93 console_flush(console);
94 console_get_size(console, col, row);
[5c058d50]95}
96
[9f1362d4]97static void screen_restart(bool clear)
[5c058d50]98{
[9f1362d4]99 screen_style_normal();
100
101 if (clear) {
[79ae36dd]102 console_flush(console);
103 console_clear(console);
[9f1362d4]104 }
[dec16a2]105
[9f1362d4]106 screen_moveto(0, 0);
[dec16a2]107}
108
[9f1362d4]109static void screen_newline(void)
[dec16a2]110{
[96b02eb9]111 sysarg_t cols;
112 sysarg_t rows;
[9f1362d4]113 screen_get_size(&cols, &rows);
114
[96b02eb9]115 sysarg_t c;
116 sysarg_t r;
[9f1362d4]117 screen_get_pos(&c, &r);
118
[96b02eb9]119 sysarg_t i;
[9f1362d4]120 for (i = c + 1; i < cols; i++)
121 puts(" ");
122
123 if (r + 1 < rows)
124 puts("\n");
125}
126
127void screen_init(void)
128{
[79ae36dd]129 console = console_init(stdin, stdout);
130
131 console_flush(console);
132 console_cursor_visibility(console, false);
[9f1362d4]133
134 screen_restart(true);
[5c058d50]135}
136
[9f1362d4]137void screen_done(void)
[79edc36]138{
[2d37006]139 free(warning_text);
140 warning_text = NULL;
141
[9f1362d4]142 screen_restart(true);
143
[79ae36dd]144 console_flush(console);
145 console_cursor_visibility(console, true);
[79edc36]146}
147
[be06914]148static void print_percent(fixed_float ffloat, unsigned int precision)
[79edc36]149{
[be06914]150 printf("%3" PRIu64 ".", ffloat.upper / ffloat.lower);
[9f1362d4]151
152 unsigned int i;
153 uint64_t rest = (ffloat.upper % ffloat.lower) * 10;
154 for (i = 0; i < precision; i++) {
155 printf("%" PRIu64, rest / ffloat.lower);
156 rest = (rest % ffloat.lower) * 10;
157 }
[be06914]158
159 printf("%%");
160}
161
162static void print_string(const char *str)
163{
[96b02eb9]164 sysarg_t cols;
165 sysarg_t rows;
[be06914]166 screen_get_size(&cols, &rows);
167
[96b02eb9]168 sysarg_t c;
169 sysarg_t r;
[be06914]170 screen_get_pos(&c, &r);
171
[0b0f4bb]172 if (c < cols) {
173 int pos = cols - c - 1;
174 printf("%.*s", pos, str);
175 }
[79edc36]176}
177
[9f1362d4]178static inline void print_global_head(data_t *data)
[dd6c71c]179{
[0b0f4bb]180 printf("top - %02lu:%02lu:%02lu up "
181 "%" PRIun " days, %02" PRIun ":%02" PRIun ":%02" PRIun ", "
182 "load average:",
[9f1362d4]183 data->hours, data->minutes, data->seconds,
184 data->udays, data->uhours, data->uminutes, data->useconds);
[dec16a2]185
186 size_t i;
187 for (i = 0; i < data->load_count; i++) {
[9f1362d4]188 puts(" ");
[dec16a2]189 stats_print_load_fragment(data->load[i], 2);
190 }
[9f1362d4]191
192 screen_newline();
[dd6c71c]193}
194
[dec16a2]195static inline void print_task_summary(data_t *data)
[dd6c71c]196{
[0b0f4bb]197 printf("tasks: %zu total", data->tasks_count);
[9f1362d4]198 screen_newline();
[dd6c71c]199}
200
[dec16a2]201static inline void print_thread_summary(data_t *data)
[638927a]202{
[dec16a2]203 size_t total = 0;
[638927a]204 size_t running = 0;
[dec16a2]205 size_t ready = 0;
206 size_t sleeping = 0;
207 size_t lingering = 0;
[638927a]208 size_t other = 0;
[dec16a2]209 size_t invalid = 0;
210
[638927a]211 size_t i;
[dec16a2]212 for (i = 0; i < data->threads_count; i++) {
213 total++;
214
215 switch (data->threads[i].state) {
216 case Running:
217 running++;
218 break;
219 case Ready:
220 ready++;
221 break;
222 case Sleeping:
223 sleeping++;
224 break;
225 case Lingering:
226 lingering++;
227 break;
228 case Entering:
229 case Exiting:
230 other++;
231 break;
232 default:
233 invalid++;
[638927a]234 }
235 }
[dec16a2]236
[0b0f4bb]237 printf("threads: %zu total, %zu running, %zu ready, "
238 "%zu sleeping, %zu lingering, %zu other, %zu invalid",
[dec16a2]239 total, running, ready, sleeping, lingering, other, invalid);
[9f1362d4]240 screen_newline();
[638927a]241}
242
[dec16a2]243static inline void print_cpu_info(data_t *data)
[8b2aba5]244{
[dec16a2]245 size_t i;
246 for (i = 0; i < data->cpus_count; i++) {
[bd01a4e]247 if (data->cpus[i].active) {
[d0c82c5]248 uint64_t busy;
249 uint64_t idle;
250 char busy_suffix;
251 char idle_suffix;
252
253 order_suffix(data->cpus[i].busy_cycles, &busy, &busy_suffix);
254 order_suffix(data->cpus[i].idle_cycles, &idle, &idle_suffix);
255
256 printf("cpu%u (%4" PRIu16 " MHz): busy cycles: "
257 "%" PRIu64 "%c, idle cycles: %" PRIu64 "%c",
[bd01a4e]258 data->cpus[i].id, data->cpus[i].frequency_mhz,
[d0c82c5]259 busy, busy_suffix, idle, idle_suffix);
[9f1362d4]260 puts(", idle: ");
[be06914]261 print_percent(data->cpus_perc[i].idle, 2);
262 puts(", busy: ");
263 print_percent(data->cpus_perc[i].busy, 2);
[bd01a4e]264 } else
[9f1362d4]265 printf("cpu%u inactive", data->cpus[i].id);
[dec16a2]266
[9f1362d4]267 screen_newline();
[8b2aba5]268 }
269}
270
[dec16a2]271static inline void print_physmem_info(data_t *data)
[516adce]272{
[dec16a2]273 uint64_t total;
274 uint64_t unavail;
275 uint64_t used;
276 uint64_t free;
[933cadf]277 const char *total_suffix;
278 const char *unavail_suffix;
279 const char *used_suffix;
280 const char *free_suffix;
[dec16a2]281
[933cadf]282 bin_order_suffix(data->physmem->total, &total, &total_suffix, false);
283 bin_order_suffix(data->physmem->unavail, &unavail, &unavail_suffix, false);
284 bin_order_suffix(data->physmem->used, &used, &used_suffix, false);
285 bin_order_suffix(data->physmem->free, &free, &free_suffix, false);
[dec16a2]286
[933cadf]287 printf("memory: %" PRIu64 "%s total, %" PRIu64 "%s unavail, %"
288 PRIu64 "%s used, %" PRIu64 "%s free", total, total_suffix,
[dec16a2]289 unavail, unavail_suffix, used, used_suffix, free, free_suffix);
[9f1362d4]290 screen_newline();
291}
292
[f682f5a]293static inline void print_help_head(void)
[9f1362d4]294{
295 screen_style_inverted();
[f682f5a]296 printf("Help");
[9f1362d4]297 screen_newline();
298 screen_style_normal();
[516adce]299}
300
[f682f5a]301static inline void print_help(void)
[8f56d93]302{
[96b02eb9]303 sysarg_t cols;
304 sysarg_t rows;
[9f1362d4]305 screen_get_size(&cols, &rows);
306
[f682f5a]307 screen_newline();
[9f1362d4]308
[f682f5a]309 printf("Operation modes:");
310 screen_newline();
[369a5f8]311
[f682f5a]312 printf(" t .. tasks statistics");
313 screen_newline();
314
315 printf(" i .. IPC statistics");
316 screen_newline();
317
318 printf(" e .. exceptions statistics");
319 screen_newline();
320
321 printf(" a .. toggle display of all/hot exceptions");
322 screen_newline();
[8f56d93]323
[f682f5a]324 printf(" h .. toggle this help screen");
[9f1362d4]325 screen_newline();
[bdfd3c97]326
[f682f5a]327 screen_newline();
328
329 printf("Other keys:");
330 screen_newline();
331
[b8d6783]332 printf(" s .. choose column to sort by");
333 screen_newline();
334
335 printf(" r .. toggle reversed sorting");
336 screen_newline();
337
[f682f5a]338 printf(" q .. quit");
339 screen_newline();
[9f1362d4]340
[96b02eb9]341 sysarg_t col;
342 sysarg_t row;
[9f1362d4]343 screen_get_pos(&col, &row);
344
[369a5f8]345 while (row < rows) {
346 screen_newline();
347 row++;
348 }
[bdfd3c97]349}
350
[f682f5a]351static inline void print_table_head(const table_t *table)
[8eec3c8]352{
[f682f5a]353 sysarg_t cols;
354 sysarg_t rows;
355 screen_get_size(&cols, &rows);
356
[8eec3c8]357 screen_style_inverted();
[f682f5a]358 for (size_t i = 0; i < table->num_columns; i++) {
359 const char *name = table->columns[i].name;
360 int width = table->columns[i].width;
361 if (i != 0) {
362 puts(" ");
363 }
364 if (width == 0) {
365 sysarg_t col;
366 sysarg_t row;
367 screen_get_pos(&col, &row);
368 width = cols - col - 1;
369 }
370 printf("[%-*.*s]", width - 2, width - 2, name);
371 }
[8eec3c8]372 screen_newline();
373 screen_style_normal();
374}
375
[f682f5a]376static inline void print_table(const table_t *table)
[8eec3c8]377{
[96b02eb9]378 sysarg_t cols;
379 sysarg_t rows;
[8eec3c8]380 screen_get_size(&cols, &rows);
381
[96b02eb9]382 sysarg_t col;
383 sysarg_t row;
[8eec3c8]384 screen_get_pos(&col, &row);
385
386 size_t i;
[f682f5a]387 for (i = 0; (i < table->num_fields) && (row < rows); i++) {
388 size_t column_index = i % table->num_columns;
389 int width = table->columns[column_index].width;
390 field_t *field = &table->fields[i];
[b3b7e14a]391
[f682f5a]392 if (column_index != 0) {
393 puts(" ");
394 }
[6484602]395
[f682f5a]396 if (width == 0) {
397 screen_get_pos(&col, &row);
398 width = cols - col - 1;
399 }
[6484602]400
[f682f5a]401 switch (field->type) {
[d76a329]402 case FIELD_EMPTY:
403 printf("%*s", width, "");
404 break;
405 case FIELD_UINT:
406 printf("%*" PRIu64, width, field->uint);
407 break;
408 case FIELD_UINT_SUFFIX_BIN: {
409 uint64_t val = field->uint;
410 const char *suffix;
411 width -= 3;
412 bin_order_suffix(val, &val, &suffix, true);
413 printf("%*" PRIu64 "%s", width, val, suffix);
414 break;
415 }
416 case FIELD_UINT_SUFFIX_DEC: {
417 uint64_t val = field->uint;
418 char suffix;
419 width -= 1;
420 order_suffix(val, &val, &suffix);
421 printf("%*" PRIu64 "%c", width, val, suffix);
422 break;
423 }
424 case FIELD_PERCENT:
425 width -= 5; /* nnn.% */
426 if (width > 2) {
427 printf("%*s", width - 2, "");
428 width = 2;
429 }
430 print_percent(field->fixed, width);
431 break;
432 case FIELD_STRING:
433 printf("%-*.*s", width, width, field->string);
434 break;
[f682f5a]435 }
[6484602]436
[f682f5a]437 if (column_index == table->num_columns - 1) {
438 screen_newline();
439 row++;
440 }
441 }
[8eec3c8]442
443 while (row < rows) {
444 screen_newline();
445 row++;
446 }
447}
448
[b8d6783]449static inline void print_sort(table_t *table)
450{
451 sysarg_t cols;
452 sysarg_t rows;
453 screen_get_size(&cols, &rows);
454
455 sysarg_t col;
456 sysarg_t row;
457 screen_get_pos(&col, &row);
458
459 size_t num = min(table->num_columns, rows - row);
460 for (size_t i = 0; i < num; i++) {
461 printf("%c - %s", table->columns[i].key, table->columns[i].name);
462 screen_newline();
463 row++;
464 }
465
466 while (row < rows) {
467 screen_newline();
468 row++;
469 }
470}
471
[f682f5a]472static inline void print_warning(void)
[2d37006]473{
474 screen_get_pos(&warning_col, &warning_row);
475 if (warning_timeleft > 0) {
476 screen_style_emphasis();
477 print_string(warning_text);
478 screen_style_normal();
479 } else {
480 free(warning_text);
481 warning_text = NULL;
482 }
483 screen_newline();
484}
485
[79edc36]486void print_data(data_t *data)
487{
[9f1362d4]488 screen_restart(false);
489 print_global_head(data);
[dec16a2]490 print_task_summary(data);
491 print_thread_summary(data);
492 print_cpu_info(data);
493 print_physmem_info(data);
[2d37006]494 print_warning();
[dec16a2]495
[f682f5a]496 switch (screen_mode) {
497 case SCREEN_TABLE:
498 print_table_head(&data->table);
499 print_table(&data->table);
[8eec3c8]500 break;
[b8d6783]501 case SCREEN_SORT:
502 print_sort(&data->table);
503 break;
[f682f5a]504 case SCREEN_HELP:
[6484602]505 print_help_head();
[b3b7e14a]506 print_help();
[bdfd3c97]507 }
[dec16a2]508
[79ae36dd]509 console_flush(console);
[dec16a2]510}
511
[2d37006]512void show_warning(const char *fmt, ...)
[dec16a2]513{
[2d37006]514 sysarg_t cols;
515 sysarg_t rows;
516 screen_get_size(&cols, &rows);
517
518 size_t warning_text_size = 1 + cols * sizeof(*warning_text);
519 free(warning_text);
520 warning_text = malloc(warning_text_size);
521 if (!warning_text)
522 return;
523
[dec16a2]524 va_list args;
525 va_start(args, fmt);
[2d37006]526 vsnprintf(warning_text, warning_text_size, fmt, args);
[dec16a2]527 va_end(args);
528
[2d37006]529 warning_timeleft = 2 * USEC_COUNT;
530
531 screen_moveto(warning_col, warning_row);
532 print_warning();
[79ae36dd]533 console_flush(console);
534}
535
536/** Get char with timeout
537 *
538 */
539int tgetchar(unsigned int sec)
540{
541 /*
542 * Reset timeleft whenever it is not positive.
543 */
544
545 if (timeleft <= 0)
546 timeleft = sec * USEC_COUNT;
547
548 /*
549 * Wait to see if there is any input. If so, take it and
550 * update timeleft so that the next call to tgetchar()
551 * will not wait as long. If there is no input,
552 * make timeleft zero and return -1.
553 */
554
555 wchar_t c = 0;
556
557 while (c == 0) {
[07b7c48]558 cons_event_t event;
[79ae36dd]559
[2d37006]560 warning_timeleft -= timeleft;
[07b7c48]561 if (!console_get_event_timeout(console, &event, &timeleft)) {
[79ae36dd]562 timeleft = 0;
563 return -1;
564 }
[2d37006]565 warning_timeleft += timeleft;
[79ae36dd]566
[07b7c48]567 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
568 c = event.ev.key.c;
[79ae36dd]569 }
570
571 return (int) c;
[79edc36]572}
573
[5c058d50]574/** @}
575 */
Note: See TracBrowser for help on using the repository browser.