00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00038 #include <stdio.h>
00039 #include <io/console.h>
00040 #include <io/style.h>
00041 #include <vfs/vfs.h>
00042 #include <stdarg.h>
00043 #include <stats.h>
00044 #include <inttypes.h>
00045 #include "screen.h"
00046 #include "top.h"
00047
00048 static sysarg_t warn_col = 0;
00049 static sysarg_t warn_row = 0;
00050
00051 static void screen_style_normal(void)
00052 {
00053 fflush(stdout);
00054 console_set_style(fphone(stdout), STYLE_NORMAL);
00055 }
00056
00057 static void screen_style_inverted(void)
00058 {
00059 fflush(stdout);
00060 console_set_style(fphone(stdout), STYLE_INVERTED);
00061 }
00062
00063 static void screen_moveto(sysarg_t col, sysarg_t row)
00064 {
00065 fflush(stdout);
00066 console_set_pos(fphone(stdout), col, row);
00067 }
00068
00069 static void screen_get_pos(sysarg_t *col, sysarg_t *row)
00070 {
00071 fflush(stdout);
00072 console_get_pos(fphone(stdout), col, row);
00073 }
00074
00075 static void screen_get_size(sysarg_t *col, sysarg_t *row)
00076 {
00077 fflush(stdout);
00078 console_get_size(fphone(stdout), col, row);
00079 }
00080
00081 static void screen_restart(bool clear)
00082 {
00083 screen_style_normal();
00084
00085 if (clear) {
00086 fflush(stdout);
00087 console_clear(fphone(stdout));
00088 }
00089
00090 screen_moveto(0, 0);
00091 }
00092
00093 static void screen_newline(void)
00094 {
00095 sysarg_t cols;
00096 sysarg_t rows;
00097 screen_get_size(&cols, &rows);
00098
00099 sysarg_t c;
00100 sysarg_t r;
00101 screen_get_pos(&c, &r);
00102
00103 sysarg_t i;
00104 for (i = c + 1; i < cols; i++)
00105 puts(" ");
00106
00107 if (r + 1 < rows)
00108 puts("\n");
00109 }
00110
00111 void screen_init(void)
00112 {
00113 fflush(stdout);
00114 console_cursor_visibility(fphone(stdout), false);
00115
00116 screen_restart(true);
00117 }
00118
00119 void screen_done(void)
00120 {
00121 screen_restart(true);
00122
00123 fflush(stdout);
00124 console_cursor_visibility(fphone(stdout), true);
00125 }
00126
00127 static void print_percent(fixed_float ffloat, unsigned int precision)
00128 {
00129 printf("%3" PRIu64 ".", ffloat.upper / ffloat.lower);
00130
00131 unsigned int i;
00132 uint64_t rest = (ffloat.upper % ffloat.lower) * 10;
00133 for (i = 0; i < precision; i++) {
00134 printf("%" PRIu64, rest / ffloat.lower);
00135 rest = (rest % ffloat.lower) * 10;
00136 }
00137
00138 printf("%%");
00139 }
00140
00141 static void print_string(const char *str)
00142 {
00143 sysarg_t cols;
00144 sysarg_t rows;
00145 screen_get_size(&cols, &rows);
00146
00147 sysarg_t c;
00148 sysarg_t r;
00149 screen_get_pos(&c, &r);
00150
00151 if (c < cols) {
00152 int pos = cols - c - 1;
00153 printf("%.*s", pos, str);
00154 }
00155 }
00156
00157 static inline void print_global_head(data_t *data)
00158 {
00159 printf("top - %02lu:%02lu:%02lu up "
00160 "%" PRIun " days, %02" PRIun ":%02" PRIun ":%02" PRIun ", "
00161 "load average:",
00162 data->hours, data->minutes, data->seconds,
00163 data->udays, data->uhours, data->uminutes, data->useconds);
00164
00165 size_t i;
00166 for (i = 0; i < data->load_count; i++) {
00167 puts(" ");
00168 stats_print_load_fragment(data->load[i], 2);
00169 }
00170
00171 screen_newline();
00172 }
00173
00174 static inline void print_task_summary(data_t *data)
00175 {
00176 printf("tasks: %zu total", data->tasks_count);
00177 screen_newline();
00178 }
00179
00180 static inline void print_thread_summary(data_t *data)
00181 {
00182 size_t total = 0;
00183 size_t running = 0;
00184 size_t ready = 0;
00185 size_t sleeping = 0;
00186 size_t lingering = 0;
00187 size_t other = 0;
00188 size_t invalid = 0;
00189
00190 size_t i;
00191 for (i = 0; i < data->threads_count; i++) {
00192 total++;
00193
00194 switch (data->threads[i].state) {
00195 case Running:
00196 running++;
00197 break;
00198 case Ready:
00199 ready++;
00200 break;
00201 case Sleeping:
00202 sleeping++;
00203 break;
00204 case Lingering:
00205 lingering++;
00206 break;
00207 case Entering:
00208 case Exiting:
00209 other++;
00210 break;
00211 default:
00212 invalid++;
00213 }
00214 }
00215
00216 printf("threads: %zu total, %zu running, %zu ready, "
00217 "%zu sleeping, %zu lingering, %zu other, %zu invalid",
00218 total, running, ready, sleeping, lingering, other, invalid);
00219 screen_newline();
00220 }
00221
00222 static inline void print_cpu_info(data_t *data)
00223 {
00224 size_t i;
00225 for (i = 0; i < data->cpus_count; i++) {
00226 if (data->cpus[i].active) {
00227 uint64_t busy;
00228 uint64_t idle;
00229 char busy_suffix;
00230 char idle_suffix;
00231
00232 order_suffix(data->cpus[i].busy_cycles, &busy, &busy_suffix);
00233 order_suffix(data->cpus[i].idle_cycles, &idle, &idle_suffix);
00234
00235 printf("cpu%u (%4" PRIu16 " MHz): busy cycles: "
00236 "%" PRIu64 "%c, idle cycles: %" PRIu64 "%c",
00237 data->cpus[i].id, data->cpus[i].frequency_mhz,
00238 busy, busy_suffix, idle, idle_suffix);
00239 puts(", idle: ");
00240 print_percent(data->cpus_perc[i].idle, 2);
00241 puts(", busy: ");
00242 print_percent(data->cpus_perc[i].busy, 2);
00243 } else
00244 printf("cpu%u inactive", data->cpus[i].id);
00245
00246 screen_newline();
00247 }
00248 }
00249
00250 static inline void print_physmem_info(data_t *data)
00251 {
00252 uint64_t total;
00253 uint64_t unavail;
00254 uint64_t used;
00255 uint64_t free;
00256 const char *total_suffix;
00257 const char *unavail_suffix;
00258 const char *used_suffix;
00259 const char *free_suffix;
00260
00261 bin_order_suffix(data->physmem->total, &total, &total_suffix, false);
00262 bin_order_suffix(data->physmem->unavail, &unavail, &unavail_suffix, false);
00263 bin_order_suffix(data->physmem->used, &used, &used_suffix, false);
00264 bin_order_suffix(data->physmem->free, &free, &free_suffix, false);
00265
00266 printf("memory: %" PRIu64 "%s total, %" PRIu64 "%s unavail, %"
00267 PRIu64 "%s used, %" PRIu64 "%s free", total, total_suffix,
00268 unavail, unavail_suffix, used, used_suffix, free, free_suffix);
00269 screen_newline();
00270 }
00271
00272 static inline void print_tasks_head(void)
00273 {
00274 screen_style_inverted();
00275 printf("[taskid] [thrds] [resident] [%%resi] [virtual] [%%virt]"
00276 " [%%user] [%%kern] [name");
00277 screen_newline();
00278 screen_style_normal();
00279 }
00280
00281 static inline void print_tasks(data_t *data)
00282 {
00283 sysarg_t cols;
00284 sysarg_t rows;
00285 screen_get_size(&cols, &rows);
00286
00287 sysarg_t col;
00288 sysarg_t row;
00289 screen_get_pos(&col, &row);
00290
00291 size_t i;
00292 for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
00293 stats_task_t *task = data->tasks + data->tasks_map[i];
00294 perc_task_t *perc = data->tasks_perc + data->tasks_map[i];
00295
00296 uint64_t resmem;
00297 const char *resmem_suffix;
00298 bin_order_suffix(task->resmem, &resmem, &resmem_suffix, true);
00299
00300 uint64_t virtmem;
00301 const char *virtmem_suffix;
00302 bin_order_suffix(task->virtmem, &virtmem, &virtmem_suffix, true);
00303
00304 printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s ",
00305 task->task_id, task->threads, resmem, resmem_suffix);
00306 print_percent(perc->resmem, 2);
00307 printf(" %6" PRIu64 "%s ", virtmem, virtmem_suffix);
00308 print_percent(perc->virtmem, 2);
00309 puts(" ");
00310 print_percent(perc->ucycles, 2);
00311 puts(" ");
00312 print_percent(perc->kcycles, 2);
00313 puts(" ");
00314 print_string(task->name);
00315
00316 screen_newline();
00317 }
00318
00319 while (row < rows) {
00320 screen_newline();
00321 row++;
00322 }
00323 }
00324
00325 static inline void print_ipc_head(void)
00326 {
00327 screen_style_inverted();
00328 printf("[taskid] [cls snt] [cls rcv] [ans snt]"
00329 " [ans rcv] [irq rcv] [forward] [name");
00330 screen_newline();
00331 screen_style_normal();
00332 }
00333
00334 static inline void print_ipc(data_t *data)
00335 {
00336 sysarg_t cols;
00337 sysarg_t rows;
00338 screen_get_size(&cols, &rows);
00339
00340 sysarg_t col;
00341 sysarg_t row;
00342 screen_get_pos(&col, &row);
00343
00344 size_t i;
00345 for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
00346 uint64_t call_sent;
00347 uint64_t call_received;
00348 uint64_t answer_sent;
00349 uint64_t answer_received;
00350 uint64_t irq_notif_received;
00351 uint64_t forwarded;
00352
00353 char call_sent_suffix;
00354 char call_received_suffix;
00355 char answer_sent_suffix;
00356 char answer_received_suffix;
00357 char irq_notif_received_suffix;
00358 char forwarded_suffix;
00359
00360 order_suffix(data->tasks[i].ipc_info.call_sent, &call_sent,
00361 &call_sent_suffix);
00362 order_suffix(data->tasks[i].ipc_info.call_received,
00363 &call_received, &call_received_suffix);
00364 order_suffix(data->tasks[i].ipc_info.answer_sent,
00365 &answer_sent, &answer_sent_suffix);
00366 order_suffix(data->tasks[i].ipc_info.answer_received,
00367 &answer_received, &answer_received_suffix);
00368 order_suffix(data->tasks[i].ipc_info.irq_notif_received,
00369 &irq_notif_received, &irq_notif_received_suffix);
00370 order_suffix(data->tasks[i].ipc_info.forwarded, &forwarded,
00371 &forwarded_suffix);
00372
00373 printf("%-8" PRIu64 " %8" PRIu64 "%c %8" PRIu64 "%c"
00374 " %8" PRIu64 "%c %8" PRIu64 "%c %8" PRIu64 "%c"
00375 " %8" PRIu64 "%c ", data->tasks[i].task_id,
00376 call_sent, call_sent_suffix,
00377 call_received, call_received_suffix,
00378 answer_sent, answer_sent_suffix,
00379 answer_received, answer_received_suffix,
00380 irq_notif_received, irq_notif_received_suffix,
00381 forwarded, forwarded_suffix);
00382 print_string(data->tasks[i].name);
00383
00384 screen_newline();
00385 }
00386
00387 while (row < rows) {
00388 screen_newline();
00389 row++;
00390 }
00391 }
00392
00393 static inline void print_excs_head(void)
00394 {
00395 screen_style_inverted();
00396 printf("[exc ] [count ] [%%count] [cycles ] [%%cycles] [description");
00397 screen_newline();
00398 screen_style_normal();
00399 }
00400
00401 static inline void print_excs(data_t *data)
00402 {
00403 sysarg_t cols;
00404 sysarg_t rows;
00405 screen_get_size(&cols, &rows);
00406
00407 sysarg_t col;
00408 sysarg_t row;
00409 screen_get_pos(&col, &row);
00410
00411 size_t i;
00412 for (i = 0; (i < data->exceptions_count) && (row < rows); i++) {
00413
00414 if ((!excs_all) && (!data->exceptions[i].hot))
00415 continue;
00416
00417 uint64_t count;
00418 uint64_t cycles;
00419
00420 char count_suffix;
00421 char cycles_suffix;
00422
00423 order_suffix(data->exceptions[i].count, &count, &count_suffix);
00424 order_suffix(data->exceptions[i].cycles, &cycles, &cycles_suffix);
00425
00426 printf("%-8u %9" PRIu64 "%c ",
00427 data->exceptions[i].id, count, count_suffix);
00428 print_percent(data->exceptions_perc[i].count, 2);
00429 printf(" %9" PRIu64 "%c ", cycles, cycles_suffix);
00430 print_percent(data->exceptions_perc[i].cycles, 2);
00431 puts(" ");
00432 print_string(data->exceptions[i].desc);
00433
00434 screen_newline();
00435 row++;
00436 }
00437
00438 while (row < rows) {
00439 screen_newline();
00440 row++;
00441 }
00442 }
00443
00444 static void print_help(void)
00445 {
00446 sysarg_t cols;
00447 sysarg_t rows;
00448 screen_get_size(&cols, &rows);
00449
00450 sysarg_t col;
00451 sysarg_t row;
00452 screen_get_pos(&col, &row);
00453
00454 screen_newline();
00455
00456 printf("Operation modes:");
00457 screen_newline();
00458
00459 printf(" t .. tasks statistics");
00460 screen_newline();
00461
00462 printf(" i .. IPC statistics");
00463 screen_newline();
00464
00465 printf(" e .. exceptions statistics");
00466 screen_newline();
00467
00468 printf(" a .. toggle display of all/hot exceptions");
00469 screen_newline();
00470
00471 row += 6;
00472
00473 while (row < rows) {
00474 screen_newline();
00475 row++;
00476 }
00477 }
00478
00479 void print_data(data_t *data)
00480 {
00481 screen_restart(false);
00482 print_global_head(data);
00483 print_task_summary(data);
00484 print_thread_summary(data);
00485 print_cpu_info(data);
00486 print_physmem_info(data);
00487
00488
00489 screen_get_pos(&warn_col, &warn_row);
00490 screen_newline();
00491
00492 switch (op_mode) {
00493 case OP_TASKS:
00494 print_tasks_head();
00495 print_tasks(data);
00496 break;
00497 case OP_IPC:
00498 print_ipc_head();
00499 print_ipc(data);
00500 break;
00501 case OP_EXCS:
00502 print_excs_head();
00503 print_excs(data);
00504 break;
00505 case OP_HELP:
00506 print_tasks_head();
00507 print_help();
00508 }
00509
00510 fflush(stdout);
00511 }
00512
00513 void print_warning(const char *fmt, ...)
00514 {
00515 screen_moveto(warn_col, warn_row);
00516
00517 va_list args;
00518 va_start(args, fmt);
00519 vprintf(fmt, args);
00520 va_end(args);
00521
00522 screen_newline();
00523 fflush(stdout);
00524 }
00525