Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/dist/src/c/demos/top/top.c

    r5042706 r9d58539  
    5555#define MINUTE  60
    5656
    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;
     57op_mode_t op_mode = OP_TASKS;
     58sort_mode_t sort_mode = SORT_TASK_CYCLES;
     59bool excs_all = false;
    13360
    13461static const char *read_data(data_t *target)
     
    14067        target->tasks = NULL;
    14168        target->tasks_perc = NULL;
     69        target->tasks_map = NULL;
    14270        target->threads = NULL;
    14371        target->exceptions = NULL;
     
    14876        target->ecycles_diff = NULL;
    14977        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;
    15578       
    15679        /* Get current time */
    15780        struct timeval time;
    158         gettimeofday(&time, NULL);
     81        if (gettimeofday(&time, NULL) != EOK)
     82                return "Cannot get time of day";
    15983       
    16084        target->hours = (time.tv_sec % DAY) / HOUR;
     
    16387       
    16488        /* 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;
    17294       
    17395        /* Get load */
     
    195117        if (target->tasks_perc == NULL)
    196118                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";
    197124       
    198125        /* Get threads */
     
    362289static int cmp_data(void *a, void *b, void *arg)
    363290{
    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       
    396304        return 0;
    397305}
    398306
    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;
     307static 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);
    532316}
    533317
     
    572356        if (target->ecount_diff != NULL)
    573357                free(target->ecount_diff);
    574 
    575         if (target->table.fields != NULL)
    576                 free(target->table.fields);
    577358}
    578359
     
    586367        printf("Reading initial data...\n");
    587368       
    588         if ((ret = read_data(&data)) != NULL)
     369        if ((ret = read_data(&data_prev)) != NULL)
    589370                goto out;
    590371       
    591372        /* Compute some rubbish to have initialised values */
    592         compute_percentages(&data, &data);
     373        compute_percentages(&data_prev, &data_prev);
    593374       
    594375        /* And paint screen until death */
    595376        while (true) {
    596377                int c = tgetchar(UPDATE_INTERVAL);
    597 
    598                 if (c < 0) { /* timeout */
    599                         data_prev = data;
     378                if (c < 0) {
    600379                        if ((ret = read_data(&data)) != NULL) {
    601                                 free_data(&data_prev);
     380                                free_data(&data);
    602381                                goto out;
    603382                        }
    604383                       
    605384                        compute_percentages(&data_prev, &data);
     385                        sort_data(&data);
     386                        print_data(&data);
    606387                        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;
    623420                                }
    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                }
    673425        }
    674426       
    675427out:
    676428        screen_done();
    677         free_data(&data);
     429        free_data(&data_prev);
    678430       
    679431        if (ret != NULL) {
Note: See TracChangeset for help on using the changeset viewer.