source: mainline/uspace/dist/src/c/demos/top/screen.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 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: 11.9 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 */
539errno_t 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.