Changes in uspace/dist/src/c/demos/top/top.c [5042706:9d58539] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/dist/src/c/demos/top/top.c
r5042706 r9d58539 55 55 #define MINUTE 60 56 56 57 typedef enum { 58 OP_TASKS, 59 OP_IPC, 60 OP_EXCS, 61 } op_mode_t; 62 63 static const column_t task_columns[] = { 64 {"taskid", 't', 8}, 65 {"thrds", 'h', 7}, 66 {"resident", 'r', 10}, 67 {"%resi", 'R', 7}, 68 {"virtual", 'v', 9}, 69 {"%virt", 'V', 7}, 70 {"%user", 'U', 7}, 71 {"%kern", 'K', 7}, 72 {"name", 'd', 0}, 73 }; 74 75 enum { 76 TASK_COL_ID = 0, 77 TASK_COL_NUM_THREADS, 78 TASK_COL_RESIDENT, 79 TASK_COL_PERCENT_RESIDENT, 80 TASK_COL_VIRTUAL, 81 TASK_COL_PERCENT_VIRTUAL, 82 TASK_COL_PERCENT_USER, 83 TASK_COL_PERCENT_KERNEL, 84 TASK_COL_NAME, 85 TASK_NUM_COLUMNS, 86 }; 87 88 static const column_t ipc_columns[] = { 89 {"taskid", 't', 8}, 90 {"cls snt", 'c', 9}, 91 {"cls rcv", 'C', 9}, 92 {"ans snt", 'a', 9}, 93 {"ans rcv", 'A', 9}, 94 {"forward", 'f', 9}, 95 {"name", 'd', 0}, 96 }; 97 98 enum { 99 IPC_COL_TASKID = 0, 100 IPC_COL_CLS_SNT, 101 IPC_COL_CLS_RCV, 102 IPC_COL_ANS_SNT, 103 IPC_COL_ANS_RCV, 104 IPC_COL_FORWARD, 105 IPC_COL_NAME, 106 IPC_NUM_COLUMNS, 107 }; 108 109 static const column_t exception_columns[] = { 110 {"exc", 'e', 8}, 111 {"count", 'n', 10}, 112 {"%count", 'N', 8}, 113 {"cycles", 'c', 10}, 114 {"%cycles", 'C', 9}, 115 {"description", 'd', 0}, 116 }; 117 118 enum { 119 EXCEPTION_COL_ID = 0, 120 EXCEPTION_COL_COUNT, 121 EXCEPTION_COL_PERCENT_COUNT, 122 EXCEPTION_COL_CYCLES, 123 EXCEPTION_COL_PERCENT_CYCLES, 124 EXCEPTION_COL_DESCRIPTION, 125 EXCEPTION_NUM_COLUMNS, 126 }; 127 128 screen_mode_t screen_mode = SCREEN_TABLE; 129 static op_mode_t op_mode = OP_TASKS; 130 static size_t sort_column = TASK_COL_PERCENT_USER; 131 static int sort_reverse = -1; 132 static bool excs_all = false; 57 op_mode_t op_mode = OP_TASKS; 58 sort_mode_t sort_mode = SORT_TASK_CYCLES; 59 bool excs_all = false; 133 60 134 61 static const char *read_data(data_t *target) … … 140 67 target->tasks = NULL; 141 68 target->tasks_perc = NULL; 69 target->tasks_map = NULL; 142 70 target->threads = NULL; 143 71 target->exceptions = NULL; … … 148 76 target->ecycles_diff = NULL; 149 77 target->ecount_diff = NULL; 150 target->table.name = NULL;151 target->table.num_columns = 0;152 target->table.columns = NULL;153 target->table.num_fields = 0;154 target->table.fields = NULL;155 78 156 79 /* Get current time */ 157 80 struct timeval time; 158 gettimeofday(&time, NULL); 81 if (gettimeofday(&time, NULL) != EOK) 82 return "Cannot get time of day"; 159 83 160 84 target->hours = (time.tv_sec % DAY) / HOUR; … … 163 87 164 88 /* Get uptime */ 165 struct timeval uptime; 166 getuptime(&uptime); 167 168 target->udays = uptime.tv_sec / DAY; 169 target->uhours = (uptime.tv_sec % DAY) / HOUR; 170 target->uminutes = (uptime.tv_sec % HOUR) / MINUTE; 171 target->useconds = uptime.tv_sec % MINUTE; 89 sysarg_t uptime = stats_get_uptime(); 90 target->udays = uptime / DAY; 91 target->uhours = (uptime % DAY) / HOUR; 92 target->uminutes = (uptime % HOUR) / MINUTE; 93 target->useconds = uptime % MINUTE; 172 94 173 95 /* Get load */ … … 195 117 if (target->tasks_perc == NULL) 196 118 return "Not enough memory for task utilization"; 119 120 target->tasks_map = 121 (size_t *) calloc(target->tasks_count, sizeof(size_t)); 122 if (target->tasks_map == NULL) 123 return "Not enough memory for task map"; 197 124 198 125 /* Get threads */ … … 362 289 static int cmp_data(void *a, void *b, void *arg) 363 290 { 364 field_t *fa = (field_t *)a + sort_column; 365 field_t *fb = (field_t *)b + sort_column; 366 367 if (fa->type > fb->type) 368 return 1 * sort_reverse; 369 370 if (fa->type < fb->type) 371 return -1 * sort_reverse; 372 373 switch (fa->type) { 374 case FIELD_EMPTY: 375 return 0; 376 case FIELD_UINT_SUFFIX_BIN: /* fallthrough */ 377 case FIELD_UINT_SUFFIX_DEC: /* fallthrough */ 378 case FIELD_UINT: 379 if (fa->uint > fb->uint) 380 return 1 * sort_reverse; 381 if (fa->uint < fb->uint) 382 return -1 * sort_reverse; 383 return 0; 384 case FIELD_PERCENT: 385 if (fa->fixed.upper * fb->fixed.lower 386 > fb->fixed.upper * fa->fixed.lower) 387 return 1 * sort_reverse; 388 if (fa->fixed.upper * fb->fixed.lower 389 < fb->fixed.upper * fa->fixed.lower) 390 return -1 * sort_reverse; 391 return 0; 392 case FIELD_STRING: 393 return str_cmp(fa->string, fb->string) * sort_reverse; 394 } 395 291 size_t ia = *((size_t *) a); 292 size_t ib = *((size_t *) b); 293 data_t *data = (data_t *) arg; 294 295 uint64_t acycles = data->ucycles_diff[ia] + data->kcycles_diff[ia]; 296 uint64_t bcycles = data->ucycles_diff[ib] + data->kcycles_diff[ib]; 297 298 if (acycles > bcycles) 299 return -1; 300 301 if (acycles < bcycles) 302 return 1; 303 396 304 return 0; 397 305 } 398 306 399 static void sort_table(table_t *table) 400 { 401 if (sort_column >= table->num_columns) 402 sort_column = 0; 403 /* stable sort is probably best, so we use gsort */ 404 gsort((void *) table->fields, table->num_fields / table->num_columns, 405 sizeof(field_t) * table->num_columns, cmp_data, NULL); 406 } 407 408 static const char *fill_task_table(data_t *data) 409 { 410 data->table.name = "Tasks"; 411 data->table.num_columns = TASK_NUM_COLUMNS; 412 data->table.columns = task_columns; 413 data->table.num_fields = data->tasks_count * TASK_NUM_COLUMNS; 414 data->table.fields = calloc(data->table.num_fields, 415 sizeof(field_t)); 416 if (data->table.fields == NULL) 417 return "Not enough memory for table fields"; 418 419 field_t *field = data->table.fields; 420 for (size_t i = 0; i < data->tasks_count; i++) { 421 stats_task_t *task = &data->tasks[i]; 422 perc_task_t *perc = &data->tasks_perc[i]; 423 field[TASK_COL_ID].type = FIELD_UINT; 424 field[TASK_COL_ID].uint = task->task_id; 425 field[TASK_COL_NUM_THREADS].type = FIELD_UINT; 426 field[TASK_COL_NUM_THREADS].uint = task->threads; 427 field[TASK_COL_RESIDENT].type = FIELD_UINT_SUFFIX_BIN; 428 field[TASK_COL_RESIDENT].uint = task->resmem; 429 field[TASK_COL_PERCENT_RESIDENT].type = FIELD_PERCENT; 430 field[TASK_COL_PERCENT_RESIDENT].fixed = perc->resmem; 431 field[TASK_COL_VIRTUAL].type = FIELD_UINT_SUFFIX_BIN; 432 field[TASK_COL_VIRTUAL].uint = task->virtmem; 433 field[TASK_COL_PERCENT_VIRTUAL].type = FIELD_PERCENT; 434 field[TASK_COL_PERCENT_VIRTUAL].fixed = perc->virtmem; 435 field[TASK_COL_PERCENT_USER].type = FIELD_PERCENT; 436 field[TASK_COL_PERCENT_USER].fixed = perc->ucycles; 437 field[TASK_COL_PERCENT_KERNEL].type = FIELD_PERCENT; 438 field[TASK_COL_PERCENT_KERNEL].fixed = perc->kcycles; 439 field[TASK_COL_NAME].type = FIELD_STRING; 440 field[TASK_COL_NAME].string = task->name; 441 field += TASK_NUM_COLUMNS; 442 } 443 444 return NULL; 445 } 446 447 static const char *fill_ipc_table(data_t *data) 448 { 449 data->table.name = "IPC"; 450 data->table.num_columns = IPC_NUM_COLUMNS; 451 data->table.columns = ipc_columns; 452 data->table.num_fields = data->tasks_count * IPC_NUM_COLUMNS; 453 data->table.fields = calloc(data->table.num_fields, 454 sizeof(field_t)); 455 if (data->table.fields == NULL) 456 return "Not enough memory for table fields"; 457 458 field_t *field = data->table.fields; 459 for (size_t i = 0; i < data->tasks_count; i++) { 460 field[IPC_COL_TASKID].type = FIELD_UINT; 461 field[IPC_COL_TASKID].uint = data->tasks[i].task_id; 462 field[IPC_COL_CLS_SNT].type = FIELD_UINT_SUFFIX_DEC; 463 field[IPC_COL_CLS_SNT].uint = data->tasks[i].ipc_info.call_sent; 464 field[IPC_COL_CLS_RCV].type = FIELD_UINT_SUFFIX_DEC; 465 field[IPC_COL_CLS_RCV].uint = data->tasks[i].ipc_info.call_received; 466 field[IPC_COL_ANS_SNT].type = FIELD_UINT_SUFFIX_DEC; 467 field[IPC_COL_ANS_SNT].uint = data->tasks[i].ipc_info.answer_sent; 468 field[IPC_COL_ANS_RCV].type = FIELD_UINT_SUFFIX_DEC; 469 field[IPC_COL_ANS_RCV].uint = data->tasks[i].ipc_info.answer_received; 470 field[IPC_COL_FORWARD].type = FIELD_UINT_SUFFIX_DEC; 471 field[IPC_COL_FORWARD].uint = data->tasks[i].ipc_info.forwarded; 472 field[IPC_COL_NAME].type = FIELD_STRING; 473 field[IPC_COL_NAME].string = data->tasks[i].name; 474 field += IPC_NUM_COLUMNS; 475 } 476 477 return NULL; 478 } 479 480 static const char *fill_exception_table(data_t *data) 481 { 482 data->table.name = "Exceptions"; 483 data->table.num_columns = EXCEPTION_NUM_COLUMNS; 484 data->table.columns = exception_columns; 485 data->table.num_fields = data->exceptions_count * 486 EXCEPTION_NUM_COLUMNS; 487 data->table.fields = calloc(data->table.num_fields, sizeof(field_t)); 488 if (data->table.fields == NULL) 489 return "Not enough memory for table fields"; 490 491 field_t *field = data->table.fields; 492 for (size_t i = 0; i < data->exceptions_count; i++) { 493 if (!excs_all && !data->exceptions[i].hot) 494 continue; 495 field[EXCEPTION_COL_ID].type = FIELD_UINT; 496 field[EXCEPTION_COL_ID].uint = data->exceptions[i].id; 497 field[EXCEPTION_COL_COUNT].type = FIELD_UINT_SUFFIX_DEC; 498 field[EXCEPTION_COL_COUNT].uint = data->exceptions[i].count; 499 field[EXCEPTION_COL_PERCENT_COUNT].type = FIELD_PERCENT; 500 field[EXCEPTION_COL_PERCENT_COUNT].fixed = data->exceptions_perc[i].count; 501 field[EXCEPTION_COL_CYCLES].type = FIELD_UINT_SUFFIX_DEC; 502 field[EXCEPTION_COL_CYCLES].uint = data->exceptions[i].cycles; 503 field[EXCEPTION_COL_PERCENT_CYCLES].type = FIELD_PERCENT; 504 field[EXCEPTION_COL_PERCENT_CYCLES].fixed = data->exceptions_perc[i].cycles; 505 field[EXCEPTION_COL_DESCRIPTION].type = FIELD_STRING; 506 field[EXCEPTION_COL_DESCRIPTION].string = data->exceptions[i].desc; 507 field += EXCEPTION_NUM_COLUMNS; 508 } 509 510 /* in case any cold exceptions were ignored */ 511 data->table.num_fields = field - data->table.fields; 512 513 return NULL; 514 } 515 516 static const char *fill_table(data_t *data) 517 { 518 if (data->table.fields != NULL) { 519 free(data->table.fields); 520 data->table.fields = NULL; 521 } 522 523 switch (op_mode) { 524 case OP_TASKS: 525 return fill_task_table(data); 526 case OP_IPC: 527 return fill_ipc_table(data); 528 case OP_EXCS: 529 return fill_exception_table(data); 530 } 531 return NULL; 307 static void sort_data(data_t *data) 308 { 309 size_t i; 310 311 for (i = 0; i < data->tasks_count; i++) 312 data->tasks_map[i] = i; 313 314 qsort((void *) data->tasks_map, data->tasks_count, 315 sizeof(size_t), cmp_data, (void *) data); 532 316 } 533 317 … … 572 356 if (target->ecount_diff != NULL) 573 357 free(target->ecount_diff); 574 575 if (target->table.fields != NULL)576 free(target->table.fields);577 358 } 578 359 … … 586 367 printf("Reading initial data...\n"); 587 368 588 if ((ret = read_data(&data )) != NULL)369 if ((ret = read_data(&data_prev)) != NULL) 589 370 goto out; 590 371 591 372 /* Compute some rubbish to have initialised values */ 592 compute_percentages(&data , &data);373 compute_percentages(&data_prev, &data_prev); 593 374 594 375 /* And paint screen until death */ 595 376 while (true) { 596 377 int c = tgetchar(UPDATE_INTERVAL); 597 598 if (c < 0) { /* timeout */ 599 data_prev = data; 378 if (c < 0) { 600 379 if ((ret = read_data(&data)) != NULL) { 601 free_data(&data _prev);380 free_data(&data); 602 381 goto out; 603 382 } 604 383 605 384 compute_percentages(&data_prev, &data); 385 sort_data(&data); 386 print_data(&data); 606 387 free_data(&data_prev); 607 608 c = -1; 609 } 610 611 if (screen_mode == SCREEN_HELP && c >= 0) { 612 if (c == 'h' || c == '?') 613 c = -1; 614 /* go back to table and handle the key */ 615 screen_mode = SCREEN_TABLE; 616 } 617 618 if (screen_mode == SCREEN_SORT && c >= 0) { 619 for (size_t i = 0; i < data.table.num_columns; i++) { 620 if (data.table.columns[i].key == c) { 621 sort_column = i; 622 screen_mode = SCREEN_TABLE; 388 data_prev = data; 389 390 continue; 391 } 392 393 switch (c) { 394 case 't': 395 print_warning("Showing task statistics"); 396 op_mode = OP_TASKS; 397 break; 398 case 'i': 399 print_warning("Showing IPC statistics"); 400 op_mode = OP_IPC; 401 break; 402 case 'e': 403 print_warning("Showing exception statistics"); 404 op_mode = OP_EXCS; 405 break; 406 case 'h': 407 print_warning("Showing help"); 408 op_mode = OP_HELP; 409 break; 410 case 'q': 411 goto out; 412 case 'a': 413 if (op_mode == OP_EXCS) { 414 excs_all = !excs_all; 415 if (excs_all) 416 print_warning("Showing all exceptions"); 417 else 418 print_warning("Showing only hot exceptions"); 419 break; 623 420 } 624 } 625 626 c = -1; 627 } 628 629 switch (c) { 630 case -1: /* do nothing */ 631 break; 632 case 't': 633 op_mode = OP_TASKS; 634 break; 635 case 'i': 636 op_mode = OP_IPC; 637 break; 638 case 'e': 639 op_mode = OP_EXCS; 640 break; 641 case 's': 642 screen_mode = SCREEN_SORT; 643 break; 644 case 'r': 645 sort_reverse = -sort_reverse; 646 break; 647 case 'h': 648 case '?': 649 screen_mode = SCREEN_HELP; 650 break; 651 case 'q': 652 goto out; 653 case 'a': 654 if (op_mode == OP_EXCS) { 655 excs_all = !excs_all; 656 if (excs_all) 657 show_warning("Showing all exceptions"); 658 else 659 show_warning("Showing only hot exceptions"); 660 break; 661 } 662 /* fallthrough */ 663 default: 664 show_warning("Unknown command \"%c\", use \"h\" for help", c); 665 continue; /* don't redraw */ 666 } 667 668 if ((ret = fill_table(&data)) != NULL) { 669 goto out; 670 } 671 sort_table(&data.table); 672 print_data(&data); 421 default: 422 print_warning("Unknown command \"%c\", use \"h\" for help", c); 423 break; 424 } 673 425 } 674 426 675 427 out: 676 428 screen_done(); 677 free_data(&data );429 free_data(&data_prev); 678 430 679 431 if (ret != NULL) {
Note:
See TracChangeset
for help on using the changeset viewer.