Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a6302ae in mainline


Ignore:
Timestamp:
2019-12-11T10:49:48Z (12 months ago)
Author:
Martin Decky <martin@…>
Branches:
master
Children:
fe7bcf1
Parents:
ad211c8
Message:

add basic support for IPC statistics

Dumping of phone connections is supported right now.

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • abi/include/abi/sysinfo.h

    rad211c8 ra6302ae  
    125125} stats_thread_t;
    126126
     127/** Statistics about a single IPC connection
     128 *
     129 */
     130typedef struct {
     131        task_id_t caller;  /**< Source task ID */
     132        task_id_t callee;  /**< Target task ID */
     133} stats_ipcc_t;
     134
    127135/** Statistics about a single exception
    128136 *
  • kernel/generic/src/sysinfo/stats.c

    rad211c8 ra6302ae  
    6969#define LOAD_INTERVAL  5
    7070
     71/** IPC connections statistics state */
     72typedef struct {
     73        bool counting;
     74        size_t count;
     75        size_t i;
     76        stats_ipcc_t *data;
     77} ipccs_state_t;
     78
    7179/** Fixed-point representation of
    7280 *
     
    371379
    372380        return ((void *) stats_threads);
     381}
     382
     383/** Produce IPC connection statistics
     384 *
     385 * Summarize IPC connection information into IPC connection statistics.
     386 *
     387 * @param cap Phone capability.
     388 * @param arg State variable.
     389 *
     390 */
     391static bool produce_stats_ipcc_cb(cap_t *cap, void *arg)
     392{
     393        phone_t *phone = cap->kobject->phone;
     394        ipccs_state_t *state = (ipccs_state_t *) arg;
     395
     396        if (state->counting) {
     397                /*
     398                 * Simply update the number of entries
     399                 * in case we are in the counting mode.
     400                 */
     401
     402                state->count++;
     403                return true;
     404        }
     405
     406        /* We are in the gathering mode */
     407
     408        if ((state->data == NULL) || (state->i >= state->count)) {
     409                /*
     410                 * Do nothing if we have no buffer
     411                 * to store the data to (meaning we are
     412                 * in a dry run) or the buffer is already
     413                 * full.
     414                 */
     415
     416                return true;
     417        }
     418
     419        mutex_lock(&phone->lock);
     420
     421        if (phone->state == IPC_PHONE_CONNECTED) {
     422                state->data[state->i].caller = phone->caller->taskid;
     423                state->data[state->i].callee = phone->callee->task->taskid;
     424                state->i++;
     425        }
     426
     427        mutex_unlock(&phone->lock);
     428
     429        return true;
     430}
     431
     432/** Get IPC connections statistics
     433 *
     434 * @param item    Sysinfo item (unused).
     435 * @param size    Size of the returned data.
     436 * @param dry_run Do not get the data, just calculate the size.
     437 * @param data    Unused.
     438 *
     439 * @return Data containing several stats_ipccs_t structures.
     440 *         If the return value is not NULL, it should be freed
     441 *         in the context of the sysinfo request.
     442 *
     443 */
     444static void *get_stats_ipccs(struct sysinfo_item *item, size_t *size,
     445    bool dry_run, void *data)
     446{
     447        /* Messing with tasks structures, avoid deadlock */
     448        irq_spinlock_lock(&tasks_lock, true);
     449
     450        ipccs_state_t state = {
     451                .counting = true,
     452                .count = 0,
     453                .i = 0,
     454                .data = NULL
     455        };
     456
     457        /* Compute the number of IPC connections */
     458        task_t *task = task_first();
     459        while (task != NULL) {
     460                task_hold(task);
     461                irq_spinlock_unlock(&tasks_lock, true);
     462
     463                caps_apply_to_kobject_type(task, KOBJECT_TYPE_PHONE,
     464                    produce_stats_ipcc_cb, &state);
     465
     466                irq_spinlock_lock(&tasks_lock, true);
     467
     468                task = task_next(task);
     469        }
     470
     471        state.counting = false;
     472        *size = sizeof(stats_ipcc_t) * state.count;
     473
     474        if (!dry_run)
     475                state.data = (stats_ipcc_t *) malloc(*size);
     476
     477        /* Gather the statistics for each task */
     478        task = task_first();
     479        while (task != NULL) {
     480                /* We already hold a reference to the task */
     481                irq_spinlock_unlock(&tasks_lock, true);
     482
     483                caps_apply_to_kobject_type(task, KOBJECT_TYPE_PHONE,
     484                    produce_stats_ipcc_cb, &state);
     485
     486                irq_spinlock_lock(&tasks_lock, true);
     487                task_release(task);
     488
     489                task = task_next(task);
     490        }
     491
     492        irq_spinlock_unlock(&tasks_lock, true);
     493
     494        return ((void *) state.data);
    373495}
    374496
     
    754876        sysinfo_set_item_gen_data("system.tasks", NULL, get_stats_tasks, NULL);
    755877        sysinfo_set_item_gen_data("system.threads", NULL, get_stats_threads, NULL);
     878        sysinfo_set_item_gen_data("system.ipccs", NULL, get_stats_ipccs, NULL);
    756879        sysinfo_set_item_gen_data("system.exceptions", NULL, get_stats_exceptions, NULL);
    757880        sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task, NULL);
  • uspace/app/stats/stats.c

    rad211c8 ra6302ae  
    5252#define MINUTE  60
    5353
     54typedef enum {
     55        LIST_TASKS,
     56        LIST_THREADS,
     57        LIST_IPCCS,
     58        LIST_CPUS,
     59        LIST_LOAD,
     60        LIST_UPTIME
     61} list_toggle_t;
     62
    5463static void list_tasks(void)
    5564{
     
    6574            " [kcycles] [name\n");
    6675
    67         size_t i;
    68         for (i = 0; i < count; i++) {
     76        for (size_t i = 0; i < count; i++) {
    6977                uint64_t resmem;
    7078                uint64_t virtmem;
     
    103111        printf("[taskid] [threadid] [state ] [prio] [cpu ] [ucycles] [kcycles]\n");
    104112
    105         size_t i;
    106         for (i = 0; i < count; i++) {
     113        for (size_t i = 0; i < count; i++) {
    107114                if ((all) || (stats_threads[i].task_id == task_id)) {
    108115                        uint64_t ucycles, kcycles;
     
    130137}
    131138
     139static void list_ipccs(task_id_t task_id, bool all)
     140{
     141        size_t count;
     142        stats_ipcc_t *stats_ipccs = stats_get_ipccs(&count);
     143
     144        if (stats_ipccs == NULL) {
     145                fprintf(stderr, "%s: Unable to get IPC connections\n", NAME);
     146                return;
     147        }
     148
     149        printf("[caller] [callee]\n");
     150
     151        for (size_t i = 0; i < count; i++) {
     152                if ((all) || (stats_ipccs[i].caller == task_id)) {
     153                        printf("%-8" PRIu64 " %-8" PRIu64 "\n",
     154                            stats_ipccs[i].caller, stats_ipccs[i].callee);
     155                }
     156        }
     157
     158        free(stats_ipccs);
     159}
     160
    132161static void list_cpus(void)
    133162{
     
    142171        printf("[id] [MHz     ] [busy cycles] [idle cycles]\n");
    143172
    144         size_t i;
    145         for (i = 0; i < count; i++) {
     173        for (size_t i = 0; i < count; i++) {
    146174                printf("%-4u ", cpus[i].id);
    147175                if (cpus[i].active) {
     
    174202        printf("%s: Load average: ", NAME);
    175203
    176         size_t i;
    177         for (i = 0; i < count; i++) {
     204        for (size_t i = 0; i < count; i++) {
    178205                if (i > 0)
    179206                        printf(" ");
     
    200227{
    201228        printf(
    202             "Usage: %s [-t task_id] [-a] [-c] [-l] [-u]\n"
     229            "Usage: %s [-t task_id] [-i task_id] [-at] [-ai] [-c] [-l] [-u]\n"
    203230            "\n"
    204231            "Options:\n"
     
    207234            "\t\tList threads of the given task\n"
    208235            "\n"
    209             "\t-a\n"
    210             "\t--all\n"
     236            "\t-i task_id\n"
     237            "\t--ipcc=task_id\n"
     238            "\t\tList IPC connections of the given task\n"
     239            "\n"
     240            "\t-at\n"
     241            "\t--all-threads\n"
    211242            "\t\tList all threads\n"
     243            "\n"
     244            "\t-ai\n"
     245            "\t--all-ipccs\n"
     246            "\t\tList all IPC connections\n"
    212247            "\n"
    213248            "\t-c\n"
     
    233268int main(int argc, char *argv[])
    234269{
    235         bool toggle_tasks = true;
    236         bool toggle_threads = false;
     270        list_toggle_t list_toggle = LIST_TASKS;
    237271        bool toggle_all = false;
    238         bool toggle_cpus = false;
    239         bool toggle_load = false;
    240         bool toggle_uptime = false;
    241 
    242272        task_id_t task_id = 0;
    243273
    244         int i;
    245         for (i = 1; i < argc; i++) {
     274        for (int i = 1; i < argc; i++) {
    246275                int off;
    247276
     
    252281                }
    253282
     283                /* All IPC connections */
     284                if ((off = arg_parse_short_long(argv[i], "-ai", "--all-ipccs")) != -1) {
     285                        list_toggle = LIST_IPCCS;
     286                        toggle_all = true;
     287                        continue;
     288                }
     289
    254290                /* All threads */
    255                 if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
    256                         toggle_tasks = false;
    257                         toggle_threads = true;
     291                if ((off = arg_parse_short_long(argv[i], "-at", "--all-threads")) != -1) {
     292                        list_toggle = LIST_THREADS;
    258293                        toggle_all = true;
    259294                        continue;
    260295                }
    261296
    262                 /* CPUs */
    263                 if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
    264                         toggle_tasks = false;
    265                         toggle_cpus = true;
    266                         continue;
    267                 }
    268 
    269                 /* Threads */
     297                /* IPC connections */
     298                if ((off = arg_parse_short_long(argv[i], "-i", "--ipcc=")) != -1) {
     299                        // TODO: Support for 64b range
     300                        int tmp;
     301                        errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
     302                        if (ret != EOK) {
     303                                printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
     304                                return -1;
     305                        }
     306
     307                        task_id = tmp;
     308
     309                        list_toggle = LIST_IPCCS;
     310                        continue;
     311                }
     312
     313                /* Tasks */
    270314                if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
    271315                        // TODO: Support for 64b range
     
    273317                        errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
    274318                        if (ret != EOK) {
    275                                 printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
     319                                printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
    276320                                return -1;
    277321                        }
     
    279323                        task_id = tmp;
    280324
    281                         toggle_tasks = false;
    282                         toggle_threads = true;
     325                        list_toggle = LIST_THREADS;
     326                        continue;
     327                }
     328
     329                /* CPUs */
     330                if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
     331                        list_toggle = LIST_CPUS;
    283332                        continue;
    284333                }
     
    286335                /* Load */
    287336                if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
    288                         toggle_tasks = false;
    289                         toggle_load = true;
     337                        list_toggle = LIST_LOAD;
    290338                        continue;
    291339                }
     
    293341                /* Uptime */
    294342                if ((off = arg_parse_short_long(argv[i], "-u", "--uptime")) != -1) {
    295                         toggle_tasks = false;
    296                         toggle_uptime = true;
    297                         continue;
    298                 }
    299         }
    300 
    301         if (toggle_tasks)
     343                        list_toggle = LIST_UPTIME;
     344                        continue;
     345                }
     346        }
     347
     348        switch (list_toggle) {
     349        case LIST_TASKS:
    302350                list_tasks();
    303 
    304         if (toggle_threads)
     351                break;
     352        case LIST_THREADS:
    305353                list_threads(task_id, toggle_all);
    306 
    307         if (toggle_cpus)
     354                break;
     355        case LIST_IPCCS:
     356                list_ipccs(task_id, toggle_all);
     357                break;
     358        case LIST_CPUS:
    308359                list_cpus();
    309 
    310         if (toggle_load)
     360                break;
     361        case LIST_LOAD:
    311362                print_load();
    312 
    313         if (toggle_uptime)
     363                break;
     364        case LIST_UPTIME:
    314365                print_uptime();
     366                break;
     367        }
    315368
    316369        return 0;
  • uspace/lib/c/generic/stats.c

    rad211c8 ra6302ae  
    184184}
    185185
     186/** Get IPC connections statistics.
     187 *
     188 * @param count Number of records returned.
     189 *
     190 * @return Array of stats_ipcc_t structures.
     191 *         If non-NULL then it should be eventually freed
     192 *         by free().
     193 *
     194 */
     195stats_ipcc_t *stats_get_ipccs(size_t *count)
     196{
     197        size_t size = 0;
     198        stats_ipcc_t *stats_ipccs =
     199            (stats_ipcc_t *) sysinfo_get_data("system.ipccs", &size);
     200
     201        if ((size % sizeof(stats_ipcc_t)) != 0) {
     202                if (stats_ipccs != NULL)
     203                        free(stats_ipccs);
     204                *count = 0;
     205                return NULL;
     206        }
     207
     208        *count = size / sizeof(stats_ipcc_t);
     209        return stats_ipccs;
     210}
     211
    186212/** Get exception statistics.
    187213 *
  • uspace/lib/c/include/stats.h

    rad211c8 ra6302ae  
    5252
    5353extern stats_thread_t *stats_get_threads(size_t *);
     54extern stats_ipcc_t *stats_get_ipccs(size_t *);
    5455
    5556extern stats_exc_t *stats_get_exceptions(size_t *);
Note: See TracChangeset for help on using the changeset viewer.