Changeset 5723313b in mainline for uspace/app/stats/stats.c


Ignore:
Timestamp:
2019-12-11T15:28:47Z (4 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
894afff
Parents:
086cab0
Message:

support generating a graph of the current run-time architecture

File:
1 edited

Legend:

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

    r086cab0 r5723313b  
    5252#define MINUTE  60
    5353
     54#define KERNEL_NAME  "kernel"
     55#define INIT_PREFIX  "init:"
     56
    5457typedef enum {
    5558        LIST_TASKS,
     
    5760        LIST_IPCCS,
    5861        LIST_CPUS,
    59         LIST_LOAD,
    60         LIST_UPTIME
    61 } list_toggle_t;
     62        PRINT_LOAD,
     63        PRINT_UPTIME,
     64        PRINT_ARCH
     65} output_toggle_t;
    6266
    6367static void list_tasks(void)
     
    224228}
    225229
     230static char *escape_dot(const char *str)
     231{
     232        size_t size = 0;
     233        for (size_t i = 0; str[i] != 0; i++) {
     234                if (str[i] == '"')
     235                        size++;
     236
     237                size++;
     238        }
     239
     240        char *escaped_str = calloc(size + 1, sizeof(char));
     241        if (escaped_str == NULL)
     242                return NULL;
     243
     244        size_t pos = 0;
     245        for (size_t i = 0; str[i] != 0; i++) {
     246                if (str[i] == '"') {
     247                        escaped_str[pos] = '\\';
     248                        pos++;
     249                }
     250
     251                escaped_str[pos] = str[i];
     252                pos++;
     253        }
     254
     255        escaped_str[pos] = 0;
     256
     257        return escaped_str;
     258}
     259
     260static void print_arch(void)
     261{
     262        size_t count_tasks;
     263        stats_task_t *stats_tasks = stats_get_tasks(&count_tasks);
     264
     265        if (stats_tasks == NULL) {
     266                fprintf(stderr, "%s: Unable to get tasks\n", NAME);
     267                return;
     268        }
     269
     270        size_t count_ipccs;
     271        stats_ipcc_t *stats_ipccs = stats_get_ipccs(&count_ipccs);
     272
     273        if (stats_ipccs == NULL) {
     274                fprintf(stderr, "%s: Unable to get IPC connections\n", NAME);
     275                return;
     276        }
     277
     278        /* Global dot language attributes */
     279        printf("digraph HelenOS {\n");
     280        printf("\tlayout=sfdp\n");
     281        printf("\t// layout=neato\n");
     282        printf("\tsplines=true\n");
     283        printf("\t// splines=ortho\n");
     284        printf("\tconcentrate=true\n");
     285        printf("\tcenter=true\n");
     286        printf("\toverlap=false\n");
     287        printf("\toutputorder=edgesfirst\n");
     288        printf("\tfontsize=12\n");
     289        printf("\tnode [shape=component style=filled color=red "
     290            "fillcolor=yellow]\n\t\n");
     291
     292        bool kernel_found = false;
     293        task_id_t kernel_id = 0;
     294
     295        /* Tasks as vertices (components) */
     296        for (size_t i = 0; i < count_tasks; i++) {
     297                /* Kernel task */
     298                bool kernel = (str_cmp(stats_tasks[i].name, KERNEL_NAME) == 0);
     299
     300                /* Init task */
     301                bool init = str_test_prefix(stats_tasks[i].name, INIT_PREFIX);
     302
     303                char *escaped_name = NULL;
     304
     305                if (init)
     306                        escaped_name = escape_dot(str_suffix(stats_tasks[i].name,
     307                            str_length(INIT_PREFIX)));
     308                else
     309                        escaped_name = escape_dot(stats_tasks[i].name);
     310
     311                if (escaped_name == NULL)
     312                        continue;
     313
     314                if (kernel) {
     315                        if (kernel_found) {
     316                                fprintf(stderr, "%s: Duplicate kernel tasks\n", NAME);
     317                        } else {
     318                                kernel_found = true;
     319                                kernel_id = stats_tasks[i].task_id;
     320                        }
     321
     322                        printf("\ttask%" PRIu64 " [label=\"%s\" shape=invtrapezium "
     323                            "fillcolor=gold]\n", stats_tasks[i].task_id, escaped_name);
     324                } else if (init)
     325                        printf("\ttask%" PRIu64 " [label=\"%s\" fillcolor=orange]\n",
     326                            stats_tasks[i].task_id, escaped_name);
     327                else
     328                        printf("\ttask%" PRIu64 " [label=\"%s\"]\n", stats_tasks[i].task_id,
     329                            escaped_name);
     330
     331                free(escaped_name);
     332        }
     333
     334        printf("\t\n");
     335
     336        if (kernel_found) {
     337                /*
     338                 * Add an invisible edge from all user
     339                 * space tasks to the kernel to increase
     340                 * the kernel ranking.
     341                 */
     342
     343                for (size_t i = 0; i < count_tasks; i++) {
     344                        /* Skip the kernel itself */
     345                        if (stats_tasks[i].task_id == kernel_id)
     346                                continue;
     347
     348                        printf("\ttask%" PRIu64 " -> task%" PRIu64 " [style=\"invis\"]\n",
     349                                    stats_tasks[i].task_id, kernel_id);
     350                }
     351        }
     352
     353        printf("\t\n");
     354
     355        /* IPC connections as edges */
     356        for (size_t i = 0; i < count_ipccs; i++) {
     357                printf("\ttask%" PRIu64 " -> task%" PRIu64 "\n",
     358                            stats_ipccs[i].caller, stats_ipccs[i].callee);
     359        }
     360
     361        printf("}\n");
     362
     363        free(stats_tasks);
     364        free(stats_ipccs);
     365}
     366
    226367static void usage(const char *name)
    227368{
    228369        printf(
    229             "Usage: %s [-t task_id] [-i task_id] [-at] [-ai] [-c] [-l] [-u]\n"
     370            "Usage: %s [-t task_id] [-i task_id] [-at] [-ai] [-c] [-l] [-u] [-d]\n"
    230371            "\n"
    231372            "Options:\n"
    232             "\t-t task_id\n"
    233             "\t--task=task_id\n"
     373            "\t-t task_id | --task=task_id\n"
    234374            "\t\tList threads of the given task\n"
    235375            "\n"
    236             "\t-i task_id\n"
    237             "\t--ipcc=task_id\n"
     376            "\t-i task_id | --ipcc=task_id\n"
    238377            "\t\tList IPC connections of the given task\n"
    239378            "\n"
    240             "\t-at\n"
    241             "\t--all-threads\n"
     379            "\t-at | --all-threads\n"
    242380            "\t\tList all threads\n"
    243381            "\n"
    244             "\t-ai\n"
    245             "\t--all-ipccs\n"
     382            "\t-ai | --all-ipccs\n"
    246383            "\t\tList all IPC connections\n"
    247384            "\n"
    248             "\t-c\n"
    249             "\t--cpus\n"
     385            "\t-c | --cpus\n"
    250386            "\t\tList CPUs\n"
    251387            "\n"
    252             "\t-l\n"
    253             "\t--load\n"
     388            "\t-l | --load\n"
    254389            "\t\tPrint system load\n"
    255390            "\n"
    256             "\t-u\n"
    257             "\t--uptime\n"
     391            "\t-u | --uptime\n"
    258392            "\t\tPrint system uptime\n"
    259393            "\n"
    260             "\t-h\n"
    261             "\t--help\n"
     394            "\t-d | --design\n"
     395            "\t\tPrint the current system architecture graph\n"
     396            "\n"
     397            "\t-h | --help\n"
    262398            "\t\tPrint this usage information\n"
    263399            "\n"
     
    268404int main(int argc, char *argv[])
    269405{
    270         list_toggle_t list_toggle = LIST_TASKS;
     406        output_toggle_t output_toggle = LIST_TASKS;
    271407        bool toggle_all = false;
    272408        task_id_t task_id = 0;
     
    283419                /* All IPC connections */
    284420                if ((off = arg_parse_short_long(argv[i], "-ai", "--all-ipccs")) != -1) {
    285                         list_toggle = LIST_IPCCS;
     421                        output_toggle = LIST_IPCCS;
    286422                        toggle_all = true;
    287423                        continue;
     
    290426                /* All threads */
    291427                if ((off = arg_parse_short_long(argv[i], "-at", "--all-threads")) != -1) {
    292                         list_toggle = LIST_THREADS;
     428                        output_toggle = LIST_THREADS;
    293429                        toggle_all = true;
    294430                        continue;
     
    307443                        task_id = tmp;
    308444
    309                         list_toggle = LIST_IPCCS;
     445                        output_toggle = LIST_IPCCS;
    310446                        continue;
    311447                }
     
    323459                        task_id = tmp;
    324460
    325                         list_toggle = LIST_THREADS;
     461                        output_toggle = LIST_THREADS;
    326462                        continue;
    327463                }
     
    329465                /* CPUs */
    330466                if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
    331                         list_toggle = LIST_CPUS;
     467                        output_toggle = LIST_CPUS;
    332468                        continue;
    333469                }
     
    335471                /* Load */
    336472                if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
    337                         list_toggle = LIST_LOAD;
     473                        output_toggle = PRINT_LOAD;
    338474                        continue;
    339475                }
     
    341477                /* Uptime */
    342478                if ((off = arg_parse_short_long(argv[i], "-u", "--uptime")) != -1) {
    343                         list_toggle = LIST_UPTIME;
    344                         continue;
    345                 }
    346         }
    347 
    348         switch (list_toggle) {
     479                        output_toggle = PRINT_UPTIME;
     480                        continue;
     481                }
     482
     483                /* Architecture */
     484                if ((off = arg_parse_short_long(argv[i], "-d", "--design")) != -1) {
     485                        output_toggle = PRINT_ARCH;
     486                        continue;
     487                }
     488        }
     489
     490        switch (output_toggle) {
    349491        case LIST_TASKS:
    350492                list_tasks();
     
    359501                list_cpus();
    360502                break;
    361         case LIST_LOAD:
     503        case PRINT_LOAD:
    362504                print_load();
    363505                break;
    364         case LIST_UPTIME:
     506        case PRINT_UPTIME:
    365507                print_uptime();
     508                break;
     509        case PRINT_ARCH:
     510                print_arch();
    366511                break;
    367512        }
Note: See TracChangeset for help on using the changeset viewer.