Changes in uspace/app/top/top.c [c0699467:b8d6783] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/top/top.c

    rc0699467 rb8d6783  
    5555#define MINUTE  60
    5656
    57 op_mode_t op_mode = OP_TASKS;
    58 sort_mode_t sort_mode = SORT_TASK_CYCLES;
    59 bool excs_all = false;
     57typedef enum {
     58        OP_TASKS,
     59        OP_IPC,
     60        OP_EXCS,
     61} op_mode_t;
     62
     63static 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
     75enum {
     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
     88static 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
     98enum {
     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
     109static 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
     118enum {
     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
     128screen_mode_t screen_mode = SCREEN_TABLE;
     129static op_mode_t op_mode = OP_TASKS;
     130static size_t sort_column = TASK_COL_PERCENT_USER;
     131static int sort_reverse = -1;
     132static bool excs_all = false;
    60133
    61134static const char *read_data(data_t *target)
     
    67140        target->tasks = NULL;
    68141        target->tasks_perc = NULL;
    69         target->tasks_map = NULL;
    70142        target->threads = NULL;
    71143        target->exceptions = NULL;
     
    76148        target->ecycles_diff = NULL;
    77149        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;
    78155       
    79156        /* Get current time */
     
    117194        if (target->tasks_perc == NULL)
    118195                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";
    124196       
    125197        /* Get threads */
     
    289361static int cmp_data(void *a, void *b, void *arg)
    290362{
    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        
     363        field_t *fa = (field_t *)a + sort_column;
     364        field_t *fb = (field_t *)b + sort_column;
     365       
     366        if (fa->type > fb->type)
     367                return 1 * sort_reverse;
     368
     369        if (fa->type < fb->type)
     370                return -1 * sort_reverse;
     371
     372        switch (fa->type) {
     373                case FIELD_EMPTY:
     374                        return 0;
     375                case FIELD_UINT_SUFFIX_BIN: /* fallthrough */
     376                case FIELD_UINT_SUFFIX_DEC: /* fallthrough */
     377                case FIELD_UINT:
     378                        if (fa->uint > fb->uint)
     379                                return 1 * sort_reverse;
     380                        if (fa->uint < fb->uint)
     381                                return -1 * sort_reverse;
     382                        return 0;
     383                case FIELD_PERCENT:
     384                        if (fa->fixed.upper * fb->fixed.lower
     385                            > fb->fixed.upper * fa->fixed.lower)
     386                                return 1 * sort_reverse;
     387                        if (fa->fixed.upper * fb->fixed.lower
     388                            < fb->fixed.upper * fa->fixed.lower)
     389                                return -1 * sort_reverse;
     390                        return 0;
     391                case FIELD_STRING:
     392                        return str_cmp(fa->string, fb->string) * sort_reverse;
     393        }
     394
    304395        return 0;
    305396}
    306397
    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);
     398static void sort_table(table_t *table)
     399{
     400        if (sort_column >= table->num_columns)
     401                sort_column = 0;
     402        /* stable sort is probably best, so we use gsort */
     403        gsort((void *) table->fields, table->num_fields / table->num_columns,
     404            sizeof(field_t) * table->num_columns, cmp_data, NULL);
     405}
     406
     407static const char *fill_task_table(data_t *data)
     408{
     409        data->table.name = "Tasks";
     410        data->table.num_columns = TASK_NUM_COLUMNS;
     411        data->table.columns = task_columns;
     412        data->table.num_fields = data->tasks_count * TASK_NUM_COLUMNS;
     413        data->table.fields = calloc(data->table.num_fields,
     414            sizeof(field_t));
     415        if (data->table.fields == NULL)
     416                return "Not enough memory for table fields";
     417
     418        field_t *field = data->table.fields;
     419        for (size_t i = 0; i < data->tasks_count; i++) {
     420                stats_task_t *task = &data->tasks[i];
     421                perc_task_t *perc = &data->tasks_perc[i];
     422                field[TASK_COL_ID].type = FIELD_UINT;
     423                field[TASK_COL_ID].uint = task->task_id;
     424                field[TASK_COL_NUM_THREADS].type = FIELD_UINT;
     425                field[TASK_COL_NUM_THREADS].uint = task->threads;
     426                field[TASK_COL_RESIDENT].type = FIELD_UINT_SUFFIX_BIN;
     427                field[TASK_COL_RESIDENT].uint = task->resmem;
     428                field[TASK_COL_PERCENT_RESIDENT].type = FIELD_PERCENT;
     429                field[TASK_COL_PERCENT_RESIDENT].fixed = perc->resmem;
     430                field[TASK_COL_VIRTUAL].type = FIELD_UINT_SUFFIX_BIN;
     431                field[TASK_COL_VIRTUAL].uint = task->virtmem;
     432                field[TASK_COL_PERCENT_VIRTUAL].type = FIELD_PERCENT;
     433                field[TASK_COL_PERCENT_VIRTUAL].fixed = perc->virtmem;
     434                field[TASK_COL_PERCENT_USER].type = FIELD_PERCENT;
     435                field[TASK_COL_PERCENT_USER].fixed = perc->ucycles;
     436                field[TASK_COL_PERCENT_KERNEL].type = FIELD_PERCENT;
     437                field[TASK_COL_PERCENT_KERNEL].fixed = perc->kcycles;
     438                field[TASK_COL_NAME].type = FIELD_STRING;
     439                field[TASK_COL_NAME].string = task->name;
     440                field += TASK_NUM_COLUMNS;
     441        }
     442
     443        return NULL;
     444}
     445
     446static const char *fill_ipc_table(data_t *data)
     447{
     448        data->table.name = "IPC";
     449        data->table.num_columns = IPC_NUM_COLUMNS;
     450        data->table.columns = ipc_columns;
     451        data->table.num_fields = data->tasks_count * IPC_NUM_COLUMNS;
     452        data->table.fields = calloc(data->table.num_fields,
     453            sizeof(field_t));
     454        if (data->table.fields == NULL)
     455                return "Not enough memory for table fields";
     456
     457        field_t *field = data->table.fields;
     458        for (size_t i = 0; i < data->tasks_count; i++) {
     459                field[IPC_COL_TASKID].type = FIELD_UINT;
     460                field[IPC_COL_TASKID].uint = data->tasks[i].task_id;
     461                field[IPC_COL_CLS_SNT].type = FIELD_UINT_SUFFIX_DEC;
     462                field[IPC_COL_CLS_SNT].uint = data->tasks[i].ipc_info.call_sent;
     463                field[IPC_COL_CLS_RCV].type = FIELD_UINT_SUFFIX_DEC;
     464                field[IPC_COL_CLS_RCV].uint = data->tasks[i].ipc_info.call_received;
     465                field[IPC_COL_ANS_SNT].type = FIELD_UINT_SUFFIX_DEC;
     466                field[IPC_COL_ANS_SNT].uint = data->tasks[i].ipc_info.answer_sent;
     467                field[IPC_COL_ANS_RCV].type = FIELD_UINT_SUFFIX_DEC;
     468                field[IPC_COL_ANS_RCV].uint = data->tasks[i].ipc_info.answer_received;
     469                field[IPC_COL_FORWARD].type = FIELD_UINT_SUFFIX_DEC;
     470                field[IPC_COL_FORWARD].uint = data->tasks[i].ipc_info.forwarded;
     471                field[IPC_COL_NAME].type = FIELD_STRING;
     472                field[IPC_COL_NAME].string = data->tasks[i].name;
     473                field += IPC_NUM_COLUMNS;
     474        }
     475
     476        return NULL;
     477}
     478
     479static const char *fill_exception_table(data_t *data)
     480{
     481        data->table.name = "Exceptions";
     482        data->table.num_columns = EXCEPTION_NUM_COLUMNS;
     483        data->table.columns = exception_columns;
     484        data->table.num_fields = data->exceptions_count *
     485            EXCEPTION_NUM_COLUMNS;
     486        data->table.fields = calloc(data->table.num_fields, sizeof(field_t));
     487        if (data->table.fields == NULL)
     488                return "Not enough memory for table fields";
     489
     490        field_t *field = data->table.fields;
     491        for (size_t i = 0; i < data->exceptions_count; i++) {
     492                if (!excs_all && !data->exceptions[i].hot)
     493                        continue;
     494                field[EXCEPTION_COL_ID].type = FIELD_UINT;
     495                field[EXCEPTION_COL_ID].uint = data->exceptions[i].id;
     496                field[EXCEPTION_COL_COUNT].type = FIELD_UINT_SUFFIX_DEC;
     497                field[EXCEPTION_COL_COUNT].uint = data->exceptions[i].count;
     498                field[EXCEPTION_COL_PERCENT_COUNT].type = FIELD_PERCENT;
     499                field[EXCEPTION_COL_PERCENT_COUNT].fixed = data->exceptions_perc[i].count;
     500                field[EXCEPTION_COL_CYCLES].type = FIELD_UINT_SUFFIX_DEC;
     501                field[EXCEPTION_COL_CYCLES].uint = data->exceptions[i].cycles;
     502                field[EXCEPTION_COL_PERCENT_CYCLES].type = FIELD_PERCENT;
     503                field[EXCEPTION_COL_PERCENT_CYCLES].fixed = data->exceptions_perc[i].cycles;
     504                field[EXCEPTION_COL_DESCRIPTION].type = FIELD_STRING;
     505                field[EXCEPTION_COL_DESCRIPTION].string = data->exceptions[i].desc;
     506                field += EXCEPTION_NUM_COLUMNS;
     507        }
     508
     509        /* in case any cold exceptions were ignored */
     510        data->table.num_fields = field - data->table.fields;
     511
     512        return NULL;
     513}
     514
     515static const char *fill_table(data_t *data)
     516{
     517        if (data->table.fields != NULL) {
     518                free(data->table.fields);
     519                data->table.fields = NULL;
     520        }
     521
     522        switch (op_mode) {
     523                case OP_TASKS:
     524                        return fill_task_table(data);
     525                case OP_IPC:
     526                        return fill_ipc_table(data);
     527                case OP_EXCS:
     528                        return fill_exception_table(data);
     529        }
     530        return NULL;
    316531}
    317532
     
    356571        if (target->ecount_diff != NULL)
    357572                free(target->ecount_diff);
     573
     574        if (target->table.fields != NULL)
     575                free(target->table.fields);
    358576}
    359577
     
    367585        printf("Reading initial data...\n");
    368586       
    369         if ((ret = read_data(&data_prev)) != NULL)
     587        if ((ret = read_data(&data)) != NULL)
    370588                goto out;
    371589       
    372590        /* Compute some rubbish to have initialised values */
    373         compute_percentages(&data_prev, &data_prev);
     591        compute_percentages(&data, &data);
    374592       
    375593        /* And paint screen until death */
    376594        while (true) {
    377595                int c = tgetchar(UPDATE_INTERVAL);
    378                 if (c < 0) {
     596
     597                if (c < 0) { /* timeout */
     598                        data_prev = data;
    379599                        if ((ret = read_data(&data)) != NULL) {
    380                                 free_data(&data);
     600                                free_data(&data_prev);
    381601                                goto out;
    382602                        }
    383603                       
    384604                        compute_percentages(&data_prev, &data);
    385                         sort_data(&data);
    386                         print_data(&data);
    387605                        free_data(&data_prev);
    388                         data_prev = data;
    389                        
    390                         continue;
    391                 }
    392                
     606
     607                        c = -1;
     608                }
     609
     610                if (screen_mode == SCREEN_HELP && c >= 0) {
     611                        if (c == 'h' || c == '?')
     612                                c = -1;
     613                        /* go back to table and handle the key */
     614                        screen_mode = SCREEN_TABLE;
     615                }
     616
     617                if (screen_mode == SCREEN_SORT && c >= 0) {
     618                        for (size_t i = 0; i < data.table.num_columns; i++) {
     619                                if (data.table.columns[i].key == c) {
     620                                        sort_column = i;
     621                                        screen_mode = SCREEN_TABLE;
     622                                }
     623                        }
     624
     625                        c = -1;
     626                }
     627
    393628                switch (c) {
     629                        case -1: /* do nothing */
     630                                break;
    394631                        case 't':
    395                                 print_warning("Showing task statistics");
    396632                                op_mode = OP_TASKS;
    397633                                break;
    398634                        case 'i':
    399                                 print_warning("Showing IPC statistics");
    400635                                op_mode = OP_IPC;
    401636                                break;
    402637                        case 'e':
    403                                 print_warning("Showing exception statistics");
    404638                                op_mode = OP_EXCS;
    405639                                break;
     640                        case 's':
     641                                screen_mode = SCREEN_SORT;
     642                                break;
     643                        case 'r':
     644                                sort_reverse = -sort_reverse;
     645                                break;
    406646                        case 'h':
    407                                 print_warning("Showing help");
    408                                 op_mode = OP_HELP;
     647                        case '?':
     648                                screen_mode = SCREEN_HELP;
    409649                                break;
    410650                        case 'q':
     
    414654                                        excs_all = !excs_all;
    415655                                        if (excs_all)
    416                                                 print_warning("Showing all exceptions");
     656                                                show_warning("Showing all exceptions");
    417657                                        else
    418                                                 print_warning("Showing only hot exceptions");
     658                                                show_warning("Showing only hot exceptions");
    419659                                        break;
    420660                                }
     661                                /* fallthrough */
    421662                        default:
    422                                 print_warning("Unknown command \"%c\", use \"h\" for help", c);
    423                                 break;
    424                 }
     663                                show_warning("Unknown command \"%c\", use \"h\" for help", c);
     664                                continue; /* don't redraw */
     665                }
     666
     667                if ((ret = fill_table(&data)) != NULL) {
     668                        goto out;
     669                }
     670                sort_table(&data.table);
     671                print_data(&data);
    425672        }
    426673       
    427674out:
    428675        screen_done();
    429         free_data(&data_prev);
     676        free_data(&data);
    430677       
    431678        if (ret != NULL) {
Note: See TracChangeset for help on using the changeset viewer.