Get rid of sys/time.h
[helenos.git] / uspace / app / top / screen.c
blob50ed550ef2c977bd0d488ffdb2d02fdd4b89b44d
1 /*
2 * Copyright (c) 2010 Stanislav Kozina
3 * Copyright (c) 2010 Martin Decky
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
30 /** @addtogroup top
31 * @brief Top utility.
32 * @{
34 /**
35 * @file
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"
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();
100 if (clear) {
101 console_flush(console);
102 console_clear(console);
105 screen_moveto(0, 0);
108 static void screen_newline(void)
110 sysarg_t cols;
111 sysarg_t rows;
112 screen_get_size(&cols, &rows);
114 sysarg_t c;
115 sysarg_t r;
116 screen_get_pos(&c, &r);
118 sysarg_t i;
119 for (i = c + 1; i < cols; i++)
120 fputs(" ", stdout);
122 if (r + 1 < rows)
123 puts("");
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)
138 free(warning_text);
139 warning_text = NULL;
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);
151 unsigned int i;
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;
158 printf("%%");
161 static void print_string(const char *str)
163 sysarg_t cols;
164 sysarg_t rows;
165 screen_get_size(&cols, &rows);
167 sysarg_t c;
168 sysarg_t r;
169 screen_get_pos(&c, &r);
171 if (c < cols) {
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 ", "
181 "load average:",
182 data->hours, data->minutes, data->seconds,
183 data->udays, data->uhours, data->uminutes, data->useconds);
185 size_t i;
186 for (i = 0; i < data->load_count; i++) {
187 fputs(" ", stdout);
188 stats_print_load_fragment(data->load[i], 2);
191 screen_newline();
194 static inline void print_task_summary(data_t *data)
196 printf("tasks: %zu total", data->tasks_count);
197 screen_newline();
200 static inline void print_thread_summary(data_t *data)
202 size_t total = 0;
203 size_t running = 0;
204 size_t ready = 0;
205 size_t sleeping = 0;
206 size_t lingering = 0;
207 size_t other = 0;
208 size_t invalid = 0;
210 size_t i;
211 for (i = 0; i < data->threads_count; i++) {
212 total++;
214 switch (data->threads[i].state) {
215 case Running:
216 running++;
217 break;
218 case Ready:
219 ready++;
220 break;
221 case Sleeping:
222 sleeping++;
223 break;
224 case Lingering:
225 lingering++;
226 break;
227 case Entering:
228 case Exiting:
229 other++;
230 break;
231 default:
232 invalid++;
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);
239 screen_newline();
242 static inline void print_cpu_info(data_t *data)
244 size_t i;
245 for (i = 0; i < data->cpus_count; i++) {
246 if (data->cpus[i].active) {
247 uint64_t busy;
248 uint64_t idle;
249 char busy_suffix;
250 char idle_suffix;
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);
263 } else
264 printf("cpu%u inactive", data->cpus[i].id);
266 screen_newline();
270 static inline void print_physmem_info(data_t *data)
272 uint64_t total;
273 uint64_t unavail;
274 uint64_t used;
275 uint64_t free;
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);
289 screen_newline();
292 static inline void print_help_head(void)
294 screen_style_inverted();
295 printf("Help");
296 screen_newline();
297 screen_style_normal();
300 static inline void print_help(void)
302 sysarg_t cols;
303 sysarg_t rows;
304 screen_get_size(&cols, &rows);
306 screen_newline();
308 printf("Operation modes:");
309 screen_newline();
311 printf(" t .. tasks statistics");
312 screen_newline();
314 printf(" i .. IPC statistics");
315 screen_newline();
317 printf(" e .. exceptions statistics");
318 screen_newline();
320 printf(" a .. toggle display of all/hot exceptions");
321 screen_newline();
323 printf(" h .. toggle this help screen");
324 screen_newline();
326 screen_newline();
328 printf("Other keys:");
329 screen_newline();
331 printf(" s .. choose column to sort by");
332 screen_newline();
334 printf(" r .. toggle reversed sorting");
335 screen_newline();
337 printf(" q .. quit");
338 screen_newline();
340 sysarg_t col;
341 sysarg_t row;
342 screen_get_pos(&col, &row);
344 while (row < rows) {
345 screen_newline();
346 row++;
350 static inline void print_table_head(const table_t *table)
352 sysarg_t cols;
353 sysarg_t rows;
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;
360 if (i != 0) {
361 fputs(" ", stdout);
363 if (width == 0) {
364 sysarg_t col;
365 sysarg_t row;
366 screen_get_pos(&col, &row);
367 width = cols - col - 1;
369 printf("[%-*.*s]", width - 2, width - 2, name);
371 screen_newline();
372 screen_style_normal();
375 static inline void print_table(const table_t *table)
377 sysarg_t cols;
378 sysarg_t rows;
379 screen_get_size(&cols, &rows);
381 sysarg_t col;
382 sysarg_t row;
383 screen_get_pos(&col, &row);
385 size_t i;
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];
390 uint64_t val;
391 const char *psuffix;
392 char suffix;
394 if (column_index != 0) {
395 fputs(" ", stdout);
398 if (width == 0) {
399 screen_get_pos(&col, &row);
400 width = cols - col - 1;
403 switch (field->type) {
404 case FIELD_EMPTY:
405 printf("%*s", width, "");
406 break;
407 case FIELD_UINT:
408 printf("%*" PRIu64, width, field->uint);
409 break;
410 case FIELD_UINT_SUFFIX_BIN:
411 val = field->uint;
412 width -= 3;
413 bin_order_suffix(val, &val, &psuffix, true);
414 printf("%*" PRIu64 "%s", width, val, psuffix);
415 break;
416 case FIELD_UINT_SUFFIX_DEC:
417 val = field->uint;
418 width -= 1;
419 order_suffix(val, &val, &suffix);
420 printf("%*" PRIu64 "%c", width, val, suffix);
421 break;
422 case FIELD_PERCENT:
423 width -= 5; /* nnn.% */
424 if (width > 2) {
425 printf("%*s", width - 2, "");
426 width = 2;
428 print_percent(field->fixed, width);
429 break;
430 case FIELD_STRING:
431 printf("%-*.*s", width, width, field->string);
432 break;
435 if (column_index == table->num_columns - 1) {
436 screen_newline();
437 row++;
441 while (row < rows) {
442 screen_newline();
443 row++;
447 static inline void print_sort(table_t *table)
449 sysarg_t cols;
450 sysarg_t rows;
451 screen_get_size(&cols, &rows);
453 sysarg_t col;
454 sysarg_t row;
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);
460 screen_newline();
461 row++;
464 while (row < rows) {
465 screen_newline();
466 row++;
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();
477 } else {
478 free(warning_text);
479 warning_text = NULL;
481 screen_newline();
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);
492 print_warning();
494 switch (screen_mode) {
495 case SCREEN_TABLE:
496 print_table_head(&data->table);
497 print_table(&data->table);
498 break;
499 case SCREEN_SORT:
500 print_sort(&data->table);
501 break;
502 case SCREEN_HELP:
503 print_help_head();
504 print_help();
507 console_flush(console);
510 void show_warning(const char *fmt, ...)
512 sysarg_t cols;
513 sysarg_t rows;
514 screen_get_size(&cols, &rows);
516 size_t warning_text_size = 1 + cols * sizeof(*warning_text);
517 free(warning_text);
518 warning_text = malloc(warning_text_size);
519 if (!warning_text)
520 return;
522 va_list args;
523 va_start(args, fmt);
524 vsnprintf(warning_text, warning_text_size, fmt, args);
525 va_end(args);
527 warning_timeleft = SEC2USEC(2);
529 screen_moveto(warning_col, warning_row);
530 print_warning();
531 console_flush(console);
534 /** Get char with timeout
537 int tgetchar(sec_t sec)
540 * Reset timeleft whenever it is not positive.
543 if (timeleft <= 0)
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.
553 wchar_t c = 0;
555 while (c == 0) {
556 cons_event_t event;
558 warning_timeleft -= timeleft;
559 if (!console_get_event_timeout(console, &event, &timeleft)) {
560 timeleft = 0;
561 return -1;
563 warning_timeleft += timeleft;
565 if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
566 c = event.ev.key.c;
569 return (int) c;
572 /** @}