source: mainline/uspace/app/top/screen.c@ 8565a42

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8565a42 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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