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

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