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
Line 
1/*
2 * Copyright (c) 2010 Stanislav Kozina
3 * Copyright (c) 2010 Martin Decky
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>
39#include <stdlib.h>
40#include <io/console.h>
41#include <io/style.h>
42#include <vfs/vfs.h>
43#include <stdarg.h>
44#include <stats.h>
45#include <inttypes.h>
46#include <macros.h>
47#include "screen.h"
48#include "top.h"
49
50#define USEC_COUNT 1000000
51
52static suseconds_t timeleft = 0;
53
54console_ctrl_t *console;
55
56static sysarg_t warning_col = 0;
57static sysarg_t warning_row = 0;
58static suseconds_t warning_timeleft = 0;
59static char *warning_text = NULL;
60
61static void screen_style_normal(void)
62{
63 console_flush(console);
64 console_set_style(console, STYLE_NORMAL);
65}
66
67static void screen_style_inverted(void)
68{
69 console_flush(console);
70 console_set_style(console, STYLE_INVERTED);
71}
72
73static void screen_style_emphasis(void)
74{
75 console_flush(console);
76 console_set_style(console, STYLE_EMPHASIS);
77}
78
79static void screen_moveto(sysarg_t col, sysarg_t row)
80{
81 console_flush(console);
82 console_set_pos(console, col, row);
83}
84
85static void screen_get_pos(sysarg_t *col, sysarg_t *row)
86{
87 console_flush(console);
88 console_get_pos(console, col, row);
89}
90
91static void screen_get_size(sysarg_t *col, sysarg_t *row)
92{
93 console_flush(console);
94 console_get_size(console, col, row);
95}
96
97static void screen_restart(bool clear)
98{
99 screen_style_normal();
100
101 if (clear) {
102 console_flush(console);
103 console_clear(console);
104 }
105
106 screen_moveto(0, 0);
107}
108
109static void screen_newline(void)
110{
111 sysarg_t cols;
112 sysarg_t rows;
113 screen_get_size(&cols, &rows);
114
115 sysarg_t c;
116 sysarg_t r;
117 screen_get_pos(&c, &r);
118
119 sysarg_t i;
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{
129 console = console_init(stdin, stdout);
130
131 console_flush(console);
132 console_cursor_visibility(console, false);
133
134 screen_restart(true);
135}
136
137void screen_done(void)
138{
139 free(warning_text);
140 warning_text = NULL;
141
142 screen_restart(true);
143
144 console_flush(console);
145 console_cursor_visibility(console, true);
146}
147
148static void print_percent(fixed_float ffloat, unsigned int precision)
149{
150 printf("%3" PRIu64 ".", ffloat.upper / ffloat.lower);
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 }
158
159 printf("%%");
160}
161
162static void print_string(const char *str)
163{
164 sysarg_t cols;
165 sysarg_t rows;
166 screen_get_size(&cols, &rows);
167
168 sysarg_t c;
169 sysarg_t r;
170 screen_get_pos(&c, &r);
171
172 if (c < cols) {
173 int pos = cols - c - 1;
174 printf("%.*s", pos, str);
175 }
176}
177
178static inline void print_global_head(data_t *data)
179{
180 printf("top - %02lu:%02lu:%02lu up "
181 "%" PRIun " days, %02" PRIun ":%02" PRIun ":%02" PRIun ", "
182 "load average:",
183 data->hours, data->minutes, data->seconds,
184 data->udays, data->uhours, data->uminutes, data->useconds);
185
186 size_t i;
187 for (i = 0; i < data->load_count; i++) {
188 puts(" ");
189 stats_print_load_fragment(data->load[i], 2);
190 }
191
192 screen_newline();
193}
194
195static inline void print_task_summary(data_t *data)
196{
197 printf("tasks: %zu total", data->tasks_count);
198 screen_newline();
199}
200
201static inline void print_thread_summary(data_t *data)
202{
203 size_t total = 0;
204 size_t running = 0;
205 size_t ready = 0;
206 size_t sleeping = 0;
207 size_t lingering = 0;
208 size_t other = 0;
209 size_t invalid = 0;
210
211 size_t i;
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++;
234 }
235 }
236
237 printf("threads: %zu total, %zu running, %zu ready, "
238 "%zu sleeping, %zu lingering, %zu other, %zu invalid",
239 total, running, ready, sleeping, lingering, other, invalid);
240 screen_newline();
241}
242
243static inline void print_cpu_info(data_t *data)
244{
245 size_t i;
246 for (i = 0; i < data->cpus_count; i++) {
247 if (data->cpus[i].active) {
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",
258 data->cpus[i].id, data->cpus[i].frequency_mhz,
259 busy, busy_suffix, idle, idle_suffix);
260 puts(", idle: ");
261 print_percent(data->cpus_perc[i].idle, 2);
262 puts(", busy: ");
263 print_percent(data->cpus_perc[i].busy, 2);
264 } else
265 printf("cpu%u inactive", data->cpus[i].id);
266
267 screen_newline();
268 }
269}
270
271static inline void print_physmem_info(data_t *data)
272{
273 uint64_t total;
274 uint64_t unavail;
275 uint64_t used;
276 uint64_t free;
277 const char *total_suffix;
278 const char *unavail_suffix;
279 const char *used_suffix;
280 const char *free_suffix;
281
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);
286
287 printf("memory: %" PRIu64 "%s total, %" PRIu64 "%s unavail, %"
288 PRIu64 "%s used, %" PRIu64 "%s free", total, total_suffix,
289 unavail, unavail_suffix, used, used_suffix, free, free_suffix);
290 screen_newline();
291}
292
293static inline void print_help_head(void)
294{
295 screen_style_inverted();
296 printf("Help");
297 screen_newline();
298 screen_style_normal();
299}
300
301static inline void print_help(void)
302{
303 sysarg_t cols;
304 sysarg_t rows;
305 screen_get_size(&cols, &rows);
306
307 screen_newline();
308
309 printf("Operation modes:");
310 screen_newline();
311
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();
323
324 printf(" h .. toggle this help screen");
325 screen_newline();
326
327 screen_newline();
328
329 printf("Other keys:");
330 screen_newline();
331
332 printf(" s .. choose column to sort by");
333 screen_newline();
334
335 printf(" r .. toggle reversed sorting");
336 screen_newline();
337
338 printf(" q .. quit");
339 screen_newline();
340
341 sysarg_t col;
342 sysarg_t row;
343 screen_get_pos(&col, &row);
344
345 while (row < rows) {
346 screen_newline();
347 row++;
348 }
349}
350
351static inline void print_table_head(const table_t *table)
352{
353 sysarg_t cols;
354 sysarg_t rows;
355 screen_get_size(&cols, &rows);
356
357 screen_style_inverted();
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 }
372 screen_newline();
373 screen_style_normal();
374}
375
376static inline void print_table(const table_t *table)
377{
378 sysarg_t cols;
379 sysarg_t rows;
380 screen_get_size(&cols, &rows);
381
382 sysarg_t col;
383 sysarg_t row;
384 screen_get_pos(&col, &row);
385
386 size_t i;
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];
391
392 if (column_index != 0) {
393 puts(" ");
394 }
395
396 if (width == 0) {
397 screen_get_pos(&col, &row);
398 width = cols - col - 1;
399 }
400
401 switch (field->type) {
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;
435 }
436
437 if (column_index == table->num_columns - 1) {
438 screen_newline();
439 row++;
440 }
441 }
442
443 while (row < rows) {
444 screen_newline();
445 row++;
446 }
447}
448
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
472static inline void print_warning(void)
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
486void print_data(data_t *data)
487{
488 screen_restart(false);
489 print_global_head(data);
490 print_task_summary(data);
491 print_thread_summary(data);
492 print_cpu_info(data);
493 print_physmem_info(data);
494 print_warning();
495
496 switch (screen_mode) {
497 case SCREEN_TABLE:
498 print_table_head(&data->table);
499 print_table(&data->table);
500 break;
501 case SCREEN_SORT:
502 print_sort(&data->table);
503 break;
504 case SCREEN_HELP:
505 print_help_head();
506 print_help();
507 }
508
509 console_flush(console);
510}
511
512void show_warning(const char *fmt, ...)
513{
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
524 va_list args;
525 va_start(args, fmt);
526 vsnprintf(warning_text, warning_text_size, fmt, args);
527 va_end(args);
528
529 warning_timeleft = 2 * USEC_COUNT;
530
531 screen_moveto(warning_col, warning_row);
532 print_warning();
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) {
558 cons_event_t event;
559
560 warning_timeleft -= timeleft;
561 if (!console_get_event_timeout(console, &event, &timeleft)) {
562 timeleft = 0;
563 return -1;
564 }
565 warning_timeleft += timeleft;
566
567 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
568 c = event.ev.key.c;
569 }
570
571 return (int) c;
572}
573
574/** @}
575 */
Note: See TracBrowser for help on using the repository browser.