LCOV - code coverage report
Current view: top level - spdk/app/spdk_top - spdk_top.c (source / functions) Hit Total Coverage
Test: Combined Lines: 0 1954 0.0 %
Date: 2024-07-10 15:22:03 Functions: 0 81 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 1192 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2020 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/jsonrpc.h"
       8                 :            : #include "spdk/rpc.h"
       9                 :            : #include "spdk/event.h"
      10                 :            : #include "spdk/util.h"
      11                 :            : #include "spdk/env.h"
      12                 :            : 
      13                 :            : #if defined __has_include
      14                 :            : #if __has_include(<ncurses/panel.h>)
      15                 :            : #include <ncurses/ncurses.h>
      16                 :            : #include <ncurses/panel.h>
      17                 :            : #include <ncurses/menu.h>
      18                 :            : #else
      19                 :            : #include <ncurses.h>
      20                 :            : #include <panel.h>
      21                 :            : #include <menu.h>
      22                 :            : #endif
      23                 :            : #else
      24                 :            : #include <ncurses.h>
      25                 :            : #include <panel.h>
      26                 :            : #include <menu.h>
      27                 :            : #endif
      28                 :            : 
      29                 :            : #define RPC_MAX_THREADS 1024
      30                 :            : #define RPC_MAX_POLLERS 1024
      31                 :            : #define RPC_MAX_CORES 1024
      32                 :            : #define MAX_THREAD_NAME 128
      33                 :            : #define MAX_POLLER_NAME 128
      34                 :            : #define MAX_THREADS 4096
      35                 :            : #define RR_MAX_VALUE 255
      36                 :            : 
      37                 :            : #define MAX_STRING_LEN 12289 /* 3x 4k monitors + 1 */
      38                 :            : #define TAB_WIN_HEIGHT 3
      39                 :            : #define TAB_WIN_LOCATION_ROW 1
      40                 :            : #define TABS_SPACING 2
      41                 :            : #define TABS_LOCATION_ROW 4
      42                 :            : #define TABS_LOCATION_COL 0
      43                 :            : #define TABS_DATA_START_ROW 3
      44                 :            : #define TABS_DATA_START_COL 2
      45                 :            : #define TABS_COL_COUNT 13
      46                 :            : #define MENU_WIN_HEIGHT 3
      47                 :            : #define MENU_WIN_SPACING 4
      48                 :            : #define MENU_WIN_LOCATION_COL 0
      49                 :            : #define RR_WIN_WIDTH 32
      50                 :            : #define RR_WIN_HEIGHT 5
      51                 :            : #define MAX_THREAD_NAME_LEN 26
      52                 :            : #define MAX_THREAD_COUNT_STR_LEN 10
      53                 :            : #define MAX_POLLER_NAME_LEN 36
      54                 :            : #define MAX_POLLER_TYPE_COUNT_STR_LEN 16
      55                 :            : #define MAX_POLLER_TYPE_STR_LEN 8
      56                 :            : #define MAX_POLLER_COUNT_STR_LEN 10
      57                 :            : #define MAX_STATUS_IND_STR_LEN 8
      58                 :            : #define MAX_POLLER_IND_STR_LEN 28
      59                 :            : #define MAX_CORE_MASK_STR_LEN 16
      60                 :            : #define MAX_CORE_STR_LEN 6
      61                 :            : #define MAX_CORE_FREQ_STR_LEN 13
      62                 :            : #define MAX_TIME_STR_LEN 12
      63                 :            : #define MAX_FLOAT_STR_LEN 8
      64                 :            : #define MAX_POLLER_RUN_COUNT 20
      65                 :            : #define MAX_PERIOD_STR_LEN 12
      66                 :            : #define MAX_INTR_LEN 6
      67                 :            : #define WINDOW_HEADER 12
      68                 :            : #define FROM_HEX 16
      69                 :            : #define THREAD_WIN_WIDTH 69
      70                 :            : #define THREAD_WIN_HEIGHT 9
      71                 :            : #define THREAD_WIN_FIRST_COL 2
      72                 :            : #define CORE_WIN_FIRST_COL 16
      73                 :            : #define CORE_WIN_WIDTH 48
      74                 :            : #define CORE_WIN_HEIGHT 11
      75                 :            : #define POLLER_WIN_HEIGHT 8
      76                 :            : #define POLLER_WIN_WIDTH 64
      77                 :            : #define POLLER_WIN_FIRST_COL 14
      78                 :            : #define FIRST_DATA_ROW 7
      79                 :            : #define HELP_WIN_WIDTH 88
      80                 :            : #define HELP_WIN_HEIGHT 24
      81                 :            : #define SCHEDULER_WIN_HEIGHT 7
      82                 :            : #define SCHEDULER_WIN_FIRST_COL 2
      83                 :            : #define MAX_SCHEDULER_PERIOD_STR_LEN 10
      84                 :            : 
      85                 :            : enum tabs {
      86                 :            :         THREADS_TAB,
      87                 :            :         POLLERS_TAB,
      88                 :            :         CORES_TAB,
      89                 :            :         NUMBER_OF_TABS,
      90                 :            : };
      91                 :            : 
      92                 :            : enum column_threads_type {
      93                 :            :         COL_THREADS_NAME,
      94                 :            :         COL_THREADS_CORE,
      95                 :            :         COL_THREADS_ACTIVE_POLLERS,
      96                 :            :         COL_THREADS_TIMED_POLLERS,
      97                 :            :         COL_THREADS_PAUSED_POLLERS,
      98                 :            :         COL_THREADS_IDLE_TIME,
      99                 :            :         COL_THREADS_BUSY_TIME,
     100                 :            :         COL_THREADS_CPU_USAGE,
     101                 :            :         COL_THREADS_STATUS,
     102                 :            :         COL_THREADS_NONE = 255,
     103                 :            : };
     104                 :            : 
     105                 :            : enum column_pollers_type {
     106                 :            :         COL_POLLERS_NAME,
     107                 :            :         COL_POLLERS_TYPE,
     108                 :            :         COL_POLLERS_THREAD_NAME,
     109                 :            :         COL_POLLERS_RUN_COUNTER,
     110                 :            :         COL_POLLERS_PERIOD,
     111                 :            :         COL_POLLERS_BUSY_COUNT,
     112                 :            :         COL_POLLERS_NONE = 255,
     113                 :            : };
     114                 :            : 
     115                 :            : enum column_cores_type {
     116                 :            :         COL_CORES_CORE,
     117                 :            :         COL_CORES_THREADS,
     118                 :            :         COL_CORES_POLLERS,
     119                 :            :         COL_CORES_IDLE_TIME,
     120                 :            :         COL_CORES_BUSY_TIME,
     121                 :            :         COL_CORES_BUSY_PCT,
     122                 :            :         COL_CORES_STATUS,
     123                 :            :         COL_CORES_INTR,
     124                 :            :         COL_CORES_SYS_PCT,
     125                 :            :         COL_CORES_IRQ_PCT,
     126                 :            :         COL_CORES_CPU_PCT,
     127                 :            :         COL_CORES_CORE_FREQ,
     128                 :            :         COL_CORES_NONE = 255,
     129                 :            : };
     130                 :            : 
     131                 :            : enum spdk_poller_type {
     132                 :            :         SPDK_ACTIVE_POLLER,
     133                 :            :         SPDK_TIMED_POLLER,
     134                 :            :         SPDK_PAUSED_POLLER,
     135                 :            :         SPDK_POLLER_TYPES_COUNT,
     136                 :            : };
     137                 :            : 
     138                 :            : struct col_desc {
     139                 :            :         const char *name;
     140                 :            :         uint8_t name_len;
     141                 :            :         uint8_t max_data_string;
     142                 :            :         bool disabled;
     143                 :            : };
     144                 :            : 
     145                 :            : struct run_counter_history {
     146                 :            :         uint64_t poller_id;
     147                 :            :         uint64_t thread_id;
     148                 :            :         uint64_t last_run_counter;
     149                 :            :         uint64_t last_busy_counter;
     150                 :            :         TAILQ_ENTRY(run_counter_history) link;
     151                 :            : };
     152                 :            : 
     153                 :            : uint8_t g_sleep_time = 1;
     154                 :            : uint16_t g_selected_row;
     155                 :            : uint16_t g_max_selected_row;
     156                 :            : uint64_t g_tick_rate;
     157                 :            : const char *poller_type_str[SPDK_POLLER_TYPES_COUNT] = {"Active", "Timed", "Paused"};
     158                 :            : const char *g_tab_title[NUMBER_OF_TABS] = {"[1] THREADS", "[2] POLLERS", "[3] CORES"};
     159                 :            : struct spdk_jsonrpc_client *g_rpc_client;
     160                 :            : static TAILQ_HEAD(, run_counter_history) g_run_counter_history = TAILQ_HEAD_INITIALIZER(
     161                 :            :                         g_run_counter_history);
     162                 :            : WINDOW *g_menu_win, *g_tab_win[NUMBER_OF_TABS], *g_tabs[NUMBER_OF_TABS];
     163                 :            : PANEL *g_panels[NUMBER_OF_TABS];
     164                 :            : uint16_t g_max_row, g_max_col;
     165                 :            : uint16_t g_data_win_size, g_max_data_rows;
     166                 :            : uint32_t g_last_threads_count, g_last_pollers_count, g_last_cores_count;
     167                 :            : uint8_t g_current_sort_col[NUMBER_OF_TABS] = {COL_THREADS_NAME, COL_POLLERS_NAME, COL_CORES_CORE};
     168                 :            : uint8_t g_current_sort_col2[NUMBER_OF_TABS] = {COL_THREADS_NONE, COL_POLLERS_NONE, COL_CORES_NONE};
     169                 :            : bool g_interval_data = true;
     170                 :            : bool g_quit_app = false;
     171                 :            : pthread_mutex_t g_thread_lock;
     172                 :            : static struct col_desc g_col_desc[NUMBER_OF_TABS][TABS_COL_COUNT] = {
     173                 :            :         {       {.name = "Thread name", .max_data_string = MAX_THREAD_NAME_LEN},
     174                 :            :                 {.name = "Core", .max_data_string = MAX_CORE_STR_LEN},
     175                 :            :                 {.name = "Active pollers", .max_data_string = MAX_POLLER_TYPE_COUNT_STR_LEN},
     176                 :            :                 {.name = "Timed pollers", .max_data_string = MAX_POLLER_TYPE_COUNT_STR_LEN},
     177                 :            :                 {.name = "Paused pollers", .max_data_string = MAX_POLLER_TYPE_COUNT_STR_LEN},
     178                 :            :                 {.name = "Idle [us]", .max_data_string = MAX_TIME_STR_LEN},
     179                 :            :                 {.name = "Busy [us]", .max_data_string = MAX_TIME_STR_LEN},
     180                 :            :                 {.name = "CPU %", .max_data_string = MAX_FLOAT_STR_LEN},
     181                 :            :                 {.name = "Status", .max_data_string = MAX_STATUS_IND_STR_LEN},
     182                 :            :                 {.name = (char *)NULL}
     183                 :            :         },
     184                 :            :         {       {.name = "Poller name", .max_data_string = MAX_POLLER_NAME_LEN},
     185                 :            :                 {.name = "Type", .max_data_string = MAX_POLLER_TYPE_STR_LEN},
     186                 :            :                 {.name = "On thread", .max_data_string = MAX_THREAD_NAME_LEN},
     187                 :            :                 {.name = "Run count", .max_data_string = MAX_POLLER_RUN_COUNT},
     188                 :            :                 {.name = "Period [us]", .max_data_string = MAX_PERIOD_STR_LEN},
     189                 :            :                 {.name = "Status (busy count)", .max_data_string = MAX_POLLER_IND_STR_LEN},
     190                 :            :                 {.name = (char *)NULL}
     191                 :            :         },
     192                 :            :         {       {.name = "Core", .max_data_string = MAX_CORE_STR_LEN},
     193                 :            :                 {.name = "Threads", .max_data_string = MAX_THREAD_COUNT_STR_LEN},
     194                 :            :                 {.name = "Pollers", .max_data_string = MAX_POLLER_COUNT_STR_LEN},
     195                 :            :                 {.name = "Idle [us]", .max_data_string = MAX_TIME_STR_LEN},
     196                 :            :                 {.name = "Busy [us]", .max_data_string = MAX_TIME_STR_LEN},
     197                 :            :                 {.name = "Busy %", .max_data_string = MAX_FLOAT_STR_LEN},
     198                 :            :                 {.name = "Status", .max_data_string = MAX_STATUS_IND_STR_LEN},
     199                 :            :                 {.name = "Intr", .max_data_string = MAX_INTR_LEN},
     200                 :            :                 {.name = "Sys %", .max_data_string = MAX_FLOAT_STR_LEN},
     201                 :            :                 {.name = "Irq %", .max_data_string = MAX_FLOAT_STR_LEN},
     202                 :            :                 {.name = "CPU %", .max_data_string = MAX_FLOAT_STR_LEN},
     203                 :            :                 {.name = "Freq [MHz]", .max_data_string = MAX_CORE_FREQ_STR_LEN},
     204                 :            :                 {.name = (char *)NULL}
     205                 :            :         }
     206                 :            : };
     207                 :            : 
     208                 :            : struct rpc_thread_info {
     209                 :            :         char *name;
     210                 :            :         uint64_t id;
     211                 :            :         int core_num;
     212                 :            :         int core_idx;
     213                 :            :         char *cpumask;
     214                 :            :         uint64_t busy;
     215                 :            :         uint64_t last_busy;
     216                 :            :         uint64_t idle;
     217                 :            :         uint64_t last_idle;
     218                 :            :         uint64_t active_pollers_count;
     219                 :            :         uint64_t timed_pollers_count;
     220                 :            :         uint64_t paused_pollers_count;
     221                 :            : };
     222                 :            : 
     223                 :            : struct rpc_poller_info {
     224                 :            :         char *name;
     225                 :            :         char *state;
     226                 :            :         uint64_t id;
     227                 :            :         uint64_t run_count;
     228                 :            :         uint64_t busy_count;
     229                 :            :         uint64_t period_ticks;
     230                 :            :         enum spdk_poller_type type;
     231                 :            :         char thread_name[MAX_THREAD_NAME];
     232                 :            :         uint64_t thread_id;
     233                 :            : };
     234                 :            : 
     235                 :            : struct rpc_core_thread_info {
     236                 :            :         char *name;
     237                 :            :         uint64_t id;
     238                 :            :         char *cpumask;
     239                 :            :         uint64_t elapsed;
     240                 :            : };
     241                 :            : 
     242                 :            : struct rpc_core_threads {
     243                 :            :         uint64_t threads_count;
     244                 :            :         struct rpc_core_thread_info *thread;
     245                 :            : };
     246                 :            : 
     247                 :            : struct rpc_core_info {
     248                 :            :         uint32_t lcore;
     249                 :            :         uint64_t pollers_count;
     250                 :            :         uint64_t busy;
     251                 :            :         uint64_t idle;
     252                 :            :         uint64_t irq;
     253                 :            :         uint64_t sys;
     254                 :            :         uint64_t usr;
     255                 :            :         uint32_t core_freq;
     256                 :            :         uint64_t last_idle;
     257                 :            :         uint64_t last_busy;
     258                 :            :         uint64_t last_sys;
     259                 :            :         uint64_t last_usr;
     260                 :            :         uint64_t last_irq;
     261                 :            :         bool in_interrupt;
     262                 :            :         struct rpc_core_threads threads;
     263                 :            :         uint64_t tid;
     264                 :            : };
     265                 :            : 
     266                 :            : struct rpc_scheduler {
     267                 :            :         char *scheduler_name;
     268                 :            :         char *governor_name;
     269                 :            :         uint64_t scheduler_period;
     270                 :            : };
     271                 :            : 
     272                 :            : struct rpc_thread_info g_threads_info[RPC_MAX_THREADS];
     273                 :            : struct rpc_poller_info g_pollers_info[RPC_MAX_POLLERS];
     274                 :            : struct rpc_core_info g_cores_info[RPC_MAX_CORES];
     275                 :            : struct rpc_scheduler g_scheduler_info;
     276                 :            : 
     277                 :            : static void
     278                 :          0 : init_str_len(void)
     279                 :            : {
     280                 :            :         int i, j;
     281                 :            : 
     282         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
     283         [ #  # ]:          0 :                 for (j = 0; g_col_desc[i][j].name != NULL; j++) {
     284         [ #  # ]:          0 :                         g_col_desc[i][j].name_len = strlen(g_col_desc[i][j].name);
     285                 :            :                 }
     286                 :            :         }
     287                 :          0 : }
     288                 :            : 
     289                 :            : static void
     290                 :          0 : free_rpc_threads_stats(struct rpc_thread_info *req)
     291                 :            : {
     292                 :          0 :         free(req->name);
     293                 :          0 :         req->name = NULL;
     294                 :          0 :         free(req->cpumask);
     295                 :          0 :         req->cpumask = NULL;
     296                 :          0 : }
     297                 :            : 
     298                 :            : static const struct spdk_json_object_decoder rpc_thread_info_decoders[] = {
     299                 :            :         {"name", offsetof(struct rpc_thread_info, name), spdk_json_decode_string},
     300                 :            :         {"id", offsetof(struct rpc_thread_info, id), spdk_json_decode_uint64},
     301                 :            :         {"cpumask", offsetof(struct rpc_thread_info, cpumask), spdk_json_decode_string},
     302                 :            :         {"busy", offsetof(struct rpc_thread_info, busy), spdk_json_decode_uint64},
     303                 :            :         {"idle", offsetof(struct rpc_thread_info, idle), spdk_json_decode_uint64},
     304                 :            :         {"active_pollers_count", offsetof(struct rpc_thread_info, active_pollers_count), spdk_json_decode_uint64},
     305                 :            :         {"timed_pollers_count", offsetof(struct rpc_thread_info, timed_pollers_count), spdk_json_decode_uint64},
     306                 :            :         {"paused_pollers_count", offsetof(struct rpc_thread_info, paused_pollers_count), spdk_json_decode_uint64},
     307                 :            : };
     308                 :            : 
     309                 :            : static int
     310                 :          0 : rpc_decode_threads_array(struct spdk_json_val *val, struct rpc_thread_info *out,
     311                 :            :                          uint64_t *current_threads_count)
     312                 :            : {
     313                 :          0 :         struct spdk_json_val *thread = val;
     314                 :          0 :         uint64_t i = 0;
     315                 :            :         int rc;
     316                 :            : 
     317                 :            :         /* Fetch the beginning of threads array */
     318                 :          0 :         rc = spdk_json_find_array(thread, "threads", NULL, &thread);
     319         [ #  # ]:          0 :         if (rc) {
     320         [ #  # ]:          0 :                 printf("Could not fetch threads array from JSON.\n");
     321                 :          0 :                 goto end;
     322                 :            :         }
     323                 :            : 
     324         [ #  # ]:          0 :         for (thread = spdk_json_array_first(thread); thread != NULL; thread = spdk_json_next(thread)) {
     325                 :          0 :                 rc = spdk_json_decode_object(thread, rpc_thread_info_decoders,
     326                 :          0 :                                              SPDK_COUNTOF(rpc_thread_info_decoders), &out[i]);
     327         [ #  # ]:          0 :                 if (rc) {
     328         [ #  # ]:          0 :                         printf("Could not decode thread object from JSON.\n");
     329                 :          0 :                         break;
     330                 :            :                 }
     331                 :            : 
     332                 :          0 :                 i++;
     333                 :            :         }
     334                 :            : 
     335                 :          0 : end:
     336                 :            : 
     337                 :          0 :         *current_threads_count = i;
     338                 :          0 :         return rc;
     339                 :            : }
     340                 :            : 
     341                 :            : static void
     342                 :          0 : free_rpc_poller(struct rpc_poller_info *poller)
     343                 :            : {
     344                 :          0 :         free(poller->name);
     345                 :          0 :         poller->name = NULL;
     346                 :          0 :         free(poller->state);
     347                 :          0 :         poller->state = NULL;
     348                 :          0 : }
     349                 :            : 
     350                 :            : static void
     351                 :          0 : free_rpc_core_info(struct rpc_core_info *core_info, size_t size)
     352                 :            : {
     353                 :            :         struct rpc_core_threads *threads;
     354                 :            :         struct rpc_core_thread_info *thread;
     355                 :            :         uint64_t i, core_number;
     356                 :            : 
     357         [ #  # ]:          0 :         for (core_number = 0; core_number < size; core_number++) {
     358                 :          0 :                 threads = &core_info[core_number].threads;
     359         [ #  # ]:          0 :                 for (i = 0; i < threads->threads_count; i++) {
     360                 :          0 :                         thread = &threads->thread[i];
     361                 :          0 :                         free(thread->name);
     362                 :          0 :                         free(thread->cpumask);
     363                 :            :                 }
     364                 :          0 :                 free(threads->thread);
     365                 :            :         }
     366                 :          0 : }
     367                 :            : 
     368                 :            : static const struct spdk_json_object_decoder rpc_pollers_decoders[] = {
     369                 :            :         {"name", offsetof(struct rpc_poller_info, name), spdk_json_decode_string},
     370                 :            :         {"state", offsetof(struct rpc_poller_info, state), spdk_json_decode_string},
     371                 :            :         {"id", offsetof(struct rpc_poller_info, id), spdk_json_decode_uint64},
     372                 :            :         {"run_count", offsetof(struct rpc_poller_info, run_count), spdk_json_decode_uint64},
     373                 :            :         {"busy_count", offsetof(struct rpc_poller_info, busy_count), spdk_json_decode_uint64},
     374                 :            :         {"period_ticks", offsetof(struct rpc_poller_info, period_ticks), spdk_json_decode_uint64, true},
     375                 :            : };
     376                 :            : 
     377                 :            : static int
     378                 :          0 : rpc_decode_pollers_array(struct spdk_json_val *poller, struct rpc_poller_info *out,
     379                 :            :                          uint64_t *poller_count,
     380                 :            :                          const char *thread_name, uint64_t thread_name_length, uint64_t thread_id,
     381                 :            :                          enum spdk_poller_type poller_type)
     382                 :            : {
     383                 :            :         int rc;
     384                 :            : 
     385         [ #  # ]:          0 :         for (poller = spdk_json_array_first(poller); poller != NULL; poller = spdk_json_next(poller)) {
     386                 :          0 :                 out[*poller_count].thread_id = thread_id;
     387   [ #  #  #  # ]:          0 :                 memcpy(out[*poller_count].thread_name, thread_name, sizeof(char) * thread_name_length);
     388                 :          0 :                 out[*poller_count].type = poller_type;
     389                 :            : 
     390                 :          0 :                 rc = spdk_json_decode_object(poller, rpc_pollers_decoders,
     391                 :          0 :                                              SPDK_COUNTOF(rpc_pollers_decoders), &out[*poller_count]);
     392         [ #  # ]:          0 :                 if (rc) {
     393         [ #  # ]:          0 :                         printf("Could not decode poller object from JSON.\n");
     394                 :          0 :                         return rc;
     395                 :            :                 }
     396                 :            : 
     397                 :          0 :                 (*poller_count)++;
     398         [ #  # ]:          0 :                 if (*poller_count == RPC_MAX_POLLERS) {
     399                 :          0 :                         return -1;
     400                 :            :                 }
     401                 :            :         }
     402                 :            : 
     403                 :          0 :         return 0;
     404                 :            : }
     405                 :            : 
     406                 :            : static const struct spdk_json_object_decoder rpc_thread_pollers_decoders[] = {
     407                 :            :         {"name", offsetof(struct rpc_thread_info, name), spdk_json_decode_string},
     408                 :            :         {"id", offsetof(struct rpc_thread_info, id), spdk_json_decode_uint64},
     409                 :            : };
     410                 :            : 
     411                 :            : static int
     412                 :          0 : rpc_decode_pollers_threads_array(struct spdk_json_val *val, struct rpc_poller_info *out,
     413                 :            :                                  uint32_t *num_pollers)
     414                 :            : {
     415                 :          0 :         struct spdk_json_val *thread = val, *poller;
     416                 :            :         /* This is a temporary poller structure to hold thread name and id.
     417                 :            :          * It is filled with data only once per thread change and then
     418                 :            :          * that memory is copied to each poller running on that thread. */
     419                 :          0 :         struct rpc_thread_info thread_info = {};
     420                 :          0 :         uint64_t poller_count = 0, i, thread_name_length;
     421                 :            :         int rc;
     422                 :          0 :         const char *poller_typenames[] = { "active_pollers", "timed_pollers", "paused_pollers" };
     423                 :          0 :         enum spdk_poller_type poller_types[] = { SPDK_ACTIVE_POLLER, SPDK_TIMED_POLLER, SPDK_PAUSED_POLLER };
     424                 :            : 
     425                 :            :         /* Fetch the beginning of threads array */
     426                 :          0 :         rc = spdk_json_find_array(thread, "threads", NULL, &thread);
     427         [ #  # ]:          0 :         if (rc) {
     428                 :          0 :                 printf("Could not fetch threads array from JSON.\n");
     429                 :          0 :                 goto end;
     430                 :            :         }
     431                 :            : 
     432         [ #  # ]:          0 :         for (thread = spdk_json_array_first(thread); thread != NULL; thread = spdk_json_next(thread)) {
     433                 :          0 :                 rc = spdk_json_decode_object_relaxed(thread, rpc_thread_pollers_decoders,
     434                 :            :                                                      SPDK_COUNTOF(rpc_thread_pollers_decoders), &thread_info);
     435         [ #  # ]:          0 :                 if (rc) {
     436                 :          0 :                         printf("Could not decode thread info from JSON.\n");
     437                 :          0 :                         goto end;
     438                 :            :                 }
     439                 :            : 
     440         [ #  # ]:          0 :                 thread_name_length = strlen(thread_info.name);
     441                 :            : 
     442         [ #  # ]:          0 :                 for (i = 0; i < SPDK_COUNTOF(poller_types); i++) {
     443                 :            :                         /* Find poller array */
     444                 :          0 :                         rc = spdk_json_find(thread, poller_typenames[i], NULL, &poller,
     445                 :            :                                             SPDK_JSON_VAL_ARRAY_BEGIN);
     446         [ #  # ]:          0 :                         if (rc) {
     447                 :          0 :                                 printf("Could not fetch pollers array from JSON.\n");
     448                 :          0 :                                 goto end;
     449                 :            :                         }
     450                 :            : 
     451                 :          0 :                         rc = rpc_decode_pollers_array(poller, out, &poller_count, thread_info.name,
     452                 :            :                                                       thread_name_length,
     453                 :          0 :                                                       thread_info.id, poller_types[i]);
     454         [ #  # ]:          0 :                         if (rc) {
     455                 :          0 :                                 printf("Could not decode the first object in pollers array.\n");
     456                 :          0 :                                 goto end;
     457                 :            :                         }
     458                 :            :                 }
     459                 :            :         }
     460                 :            : 
     461                 :          0 :         *num_pollers = poller_count;
     462                 :            : 
     463                 :          0 : end:
     464                 :            :         /* Since we rely in spdk_json_object_decode() to free this value
     465                 :            :          * each time we rewrite it, we need to free the last allocation
     466                 :            :          * manually. */
     467                 :          0 :         free(thread_info.name);
     468                 :            : 
     469         [ #  # ]:          0 :         if (rc) {
     470                 :          0 :                 *num_pollers = 0;
     471         [ #  # ]:          0 :                 for (i = 0; i < poller_count; i++) {
     472                 :          0 :                         free_rpc_poller(&out[i]);
     473                 :            :                 }
     474                 :            :         }
     475                 :            : 
     476                 :          0 :         return rc;
     477                 :            : }
     478                 :            : 
     479                 :            : static const struct spdk_json_object_decoder rpc_core_thread_info_decoders[] = {
     480                 :            :         {"name", offsetof(struct rpc_core_thread_info, name), spdk_json_decode_string},
     481                 :            :         {"id", offsetof(struct rpc_core_thread_info, id), spdk_json_decode_uint64},
     482                 :            :         {"cpumask", offsetof(struct rpc_core_thread_info, cpumask), spdk_json_decode_string},
     483                 :            :         {"elapsed", offsetof(struct rpc_core_thread_info, elapsed), spdk_json_decode_uint64},
     484                 :            : };
     485                 :            : 
     486                 :            : static int
     487                 :          0 : rpc_decode_core_threads_object(const struct spdk_json_val *val, void *out)
     488                 :            : {
     489                 :          0 :         struct rpc_core_thread_info *info = out;
     490                 :            : 
     491                 :          0 :         return spdk_json_decode_object(val, rpc_core_thread_info_decoders,
     492                 :            :                                        SPDK_COUNTOF(rpc_core_thread_info_decoders), info);
     493                 :            : }
     494                 :            : 
     495                 :            : #define RPC_THREAD_ENTRY_SIZE (SPDK_COUNTOF(rpc_core_thread_info_decoders) * 2)
     496                 :            : 
     497                 :            : static int
     498                 :          0 : rpc_decode_cores_lw_threads(const struct spdk_json_val *val, void *out)
     499                 :            : {
     500                 :          0 :         struct rpc_core_threads *threads = out;
     501                 :            :         /* The number of thread entries received from RPC can be calculated using
     502                 :            :          * above define value (each JSON line = key + value, hence '* 2' ) and JSON
     503                 :            :          * 'val' value (-2 is to subtract VAL_OBJECT_BEGIN/END). */
     504                 :          0 :         uint16_t threads_count = (spdk_json_val_len(val) - 2) / RPC_THREAD_ENTRY_SIZE;
     505                 :            : 
     506         [ #  # ]:          0 :         assert(threads != NULL);
     507                 :          0 :         threads->thread = calloc(threads_count, sizeof(struct rpc_core_thread_info));
     508                 :            : 
     509                 :          0 :         return spdk_json_decode_array(val, rpc_decode_core_threads_object, threads->thread, threads_count,
     510                 :          0 :                                       &threads->threads_count, sizeof(struct rpc_core_thread_info));
     511                 :            : }
     512                 :            : 
     513                 :            : static const struct spdk_json_object_decoder rpc_core_info_decoders[] = {
     514                 :            :         {"lcore", offsetof(struct rpc_core_info, lcore), spdk_json_decode_uint32},
     515                 :            :         {"busy", offsetof(struct rpc_core_info, busy), spdk_json_decode_uint64},
     516                 :            :         {"idle", offsetof(struct rpc_core_info, idle), spdk_json_decode_uint64},
     517                 :            :         {"irq", offsetof(struct rpc_core_info, irq), spdk_json_decode_uint64},
     518                 :            :         {"sys", offsetof(struct rpc_core_info, sys), spdk_json_decode_uint64},
     519                 :            :         {"usr", offsetof(struct rpc_core_info, usr), spdk_json_decode_uint64},
     520                 :            :         {"core_freq", offsetof(struct rpc_core_info, core_freq), spdk_json_decode_uint32, true},
     521                 :            :         {"in_interrupt", offsetof(struct rpc_core_info, in_interrupt), spdk_json_decode_bool},
     522                 :            :         {"lw_threads", offsetof(struct rpc_core_info, threads), rpc_decode_cores_lw_threads},
     523                 :            :         {"tid", offsetof(struct rpc_core_info, tid), spdk_json_decode_uint64},
     524                 :            : };
     525                 :            : 
     526                 :            : static int
     527                 :          0 : rpc_decode_core_object(const struct spdk_json_val *val, void *out)
     528                 :            : {
     529                 :          0 :         struct rpc_core_info *info = out;
     530                 :            : 
     531                 :          0 :         return spdk_json_decode_object(val, rpc_core_info_decoders,
     532                 :            :                                        SPDK_COUNTOF(rpc_core_info_decoders), info);
     533                 :            : }
     534                 :            : 
     535                 :            : static int
     536                 :          0 : rpc_decode_cores_array(struct spdk_json_val *val, struct rpc_core_info *out,
     537                 :            :                        uint32_t *current_cores_count)
     538                 :            : {
     539                 :          0 :         struct spdk_json_val *core = val;
     540                 :          0 :         size_t cores_count;
     541                 :            :         int rc;
     542                 :            : 
     543                 :            :         /* Fetch the beginning of reactors array. */
     544                 :          0 :         rc = spdk_json_find_array(core, "reactors", NULL, &core);
     545         [ #  # ]:          0 :         if (rc) {
     546         [ #  # ]:          0 :                 printf("Could not fetch cores array from JSON.");
     547                 :          0 :                 goto end;
     548                 :            :         }
     549                 :            : 
     550                 :          0 :         rc = spdk_json_decode_array(core, rpc_decode_core_object, out, RPC_MAX_CORES, &cores_count,
     551                 :            :                                     sizeof(struct rpc_core_info));
     552                 :            : 
     553                 :          0 :         *current_cores_count = (uint32_t)cores_count;
     554                 :            : 
     555                 :          0 : end:
     556                 :          0 :         return rc;
     557                 :            : }
     558                 :            : 
     559                 :            : static void
     560                 :          0 : free_rpc_scheduler(struct rpc_scheduler *req)
     561                 :            : {
     562                 :          0 :         free(req->scheduler_name);
     563                 :          0 :         free(req->governor_name);
     564                 :          0 : }
     565                 :            : 
     566                 :            : static const struct spdk_json_object_decoder rpc_scheduler_decoders[] = {
     567                 :            :         {"scheduler_name", offsetof(struct rpc_scheduler, scheduler_name), spdk_json_decode_string, true},
     568                 :            :         {"governor_name", offsetof(struct rpc_scheduler, governor_name), spdk_json_decode_string, true},
     569                 :            :         {"scheduler_period", offsetof(struct rpc_scheduler, scheduler_period), spdk_json_decode_uint64},
     570                 :            : };
     571                 :            : 
     572                 :            : static int
     573                 :          0 : rpc_send_req(char *rpc_name, struct spdk_jsonrpc_client_response **resp)
     574                 :            : {
     575                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
     576                 :            :         struct spdk_json_write_ctx *w;
     577                 :            :         struct spdk_jsonrpc_client_request *request;
     578                 :            :         int rc;
     579                 :            : 
     580                 :          0 :         request = spdk_jsonrpc_client_create_request();
     581         [ #  # ]:          0 :         if (request == NULL) {
     582                 :          0 :                 return -ENOMEM;
     583                 :            :         }
     584                 :            : 
     585                 :          0 :         w = spdk_jsonrpc_begin_request(request, 1, rpc_name);
     586                 :          0 :         spdk_jsonrpc_end_request(request, w);
     587                 :          0 :         spdk_jsonrpc_client_send_request(g_rpc_client, request);
     588                 :            : 
     589                 :            :         do {
     590                 :          0 :                 rc = spdk_jsonrpc_client_poll(g_rpc_client, 1);
     591   [ #  #  #  # ]:          0 :         } while (rc == 0 || rc == -ENOTCONN);
     592                 :            : 
     593         [ #  # ]:          0 :         if (rc <= 0) {
     594                 :          0 :                 return -1;
     595                 :            :         }
     596                 :            : 
     597                 :          0 :         json_resp = spdk_jsonrpc_client_get_response(g_rpc_client);
     598         [ #  # ]:          0 :         if (json_resp == NULL) {
     599                 :          0 :                 return -1;
     600                 :            :         }
     601                 :            : 
     602                 :            :         /* Check for error response */
     603         [ #  # ]:          0 :         if (json_resp->error != NULL) {
     604                 :          0 :                 spdk_jsonrpc_client_free_response(json_resp);
     605                 :          0 :                 return -1;
     606                 :            :         }
     607                 :            : 
     608         [ #  # ]:          0 :         assert(json_resp->result);
     609                 :            : 
     610                 :          0 :         *resp = json_resp;
     611                 :            : 
     612                 :          0 :         return 0;
     613                 :            : }
     614                 :            : 
     615                 :            : static uint64_t
     616                 :          0 : get_cpu_usage(uint64_t busy_ticks, uint64_t idle_ticks)
     617                 :            : {
     618         [ #  # ]:          0 :         if (busy_ticks + idle_ticks > 0) {
     619                 :            :                 /* Increase numerator to convert fraction into decimal with
     620                 :            :                  * additional precision */
     621         [ #  # ]:          0 :                 return busy_ticks * 10000 / (busy_ticks + idle_ticks);
     622                 :            :         }
     623                 :            : 
     624                 :          0 :         return 0;
     625                 :            : }
     626                 :            : 
     627                 :            : static int
     628                 :          0 : subsort_threads(enum column_threads_type sort_column, const void *p1, const void *p2)
     629                 :            : {
     630                 :          0 :         const struct rpc_thread_info thread_info1 = *(struct rpc_thread_info *)p1;
     631                 :          0 :         const struct rpc_thread_info thread_info2 = *(struct rpc_thread_info *)p2;
     632                 :            :         uint64_t count1, count2;
     633                 :            : 
     634   [ #  #  #  #  :          0 :         switch (sort_column) {
             #  #  #  #  
                      # ]
     635                 :          0 :         case COL_THREADS_NAME:
     636   [ #  #  #  # ]:          0 :                 return strcmp(thread_info1.name, thread_info2.name);
     637                 :          0 :         case COL_THREADS_CORE:
     638                 :          0 :                 count2 = thread_info1.core_num;
     639                 :          0 :                 count1 = thread_info2.core_num;
     640                 :          0 :                 break;
     641                 :          0 :         case COL_THREADS_ACTIVE_POLLERS:
     642                 :          0 :                 count1 = thread_info1.active_pollers_count;
     643                 :          0 :                 count2 = thread_info2.active_pollers_count;
     644                 :          0 :                 break;
     645                 :          0 :         case COL_THREADS_TIMED_POLLERS:
     646                 :          0 :                 count1 = thread_info1.timed_pollers_count;
     647                 :          0 :                 count2 = thread_info2.timed_pollers_count;
     648                 :          0 :                 break;
     649                 :          0 :         case COL_THREADS_PAUSED_POLLERS:
     650                 :          0 :                 count1 = thread_info1.paused_pollers_count;
     651                 :          0 :                 count2 = thread_info2.paused_pollers_count;
     652                 :          0 :                 break;
     653                 :          0 :         case COL_THREADS_IDLE_TIME:
     654   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     655                 :          0 :                         count1 = thread_info1.idle - thread_info1.last_idle;
     656                 :          0 :                         count2 = thread_info2.idle - thread_info2.last_idle;
     657                 :            :                 } else {
     658                 :          0 :                         count1 = thread_info1.idle;
     659                 :          0 :                         count2 = thread_info2.idle;
     660                 :            :                 }
     661                 :          0 :                 break;
     662                 :          0 :         case COL_THREADS_BUSY_TIME:
     663   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     664                 :          0 :                         count1 = thread_info1.busy - thread_info1.last_busy;
     665                 :          0 :                         count2 = thread_info2.busy - thread_info2.last_busy;
     666                 :            :                 } else {
     667                 :          0 :                         count1 = thread_info1.busy;
     668                 :          0 :                         count2 = thread_info2.busy;
     669                 :            :                 }
     670                 :          0 :                 break;
     671                 :          0 :         case COL_THREADS_CPU_USAGE:
     672                 :          0 :                 count1 = get_cpu_usage(thread_info1.busy - thread_info1.last_busy,
     673                 :          0 :                                        g_cores_info[thread_info1.core_idx].busy + g_cores_info[thread_info1.core_idx].idle);
     674                 :          0 :                 count2 = get_cpu_usage(thread_info2.busy - thread_info2.last_busy,
     675                 :          0 :                                        g_cores_info[thread_info2.core_idx].busy + g_cores_info[thread_info2.core_idx].idle);
     676                 :          0 :                 break;
     677                 :          0 :         case COL_THREADS_NONE:
     678                 :            :         default:
     679                 :          0 :                 return 0;
     680                 :            :         }
     681                 :            : 
     682         [ #  # ]:          0 :         if (count2 > count1) {
     683                 :          0 :                 return 1;
     684         [ #  # ]:          0 :         } else if (count2 < count1) {
     685                 :          0 :                 return -1;
     686                 :            :         } else {
     687                 :          0 :                 return 0;
     688                 :            :         }
     689                 :            : }
     690                 :            : 
     691                 :            : static int
     692                 :          0 : sort_threads(const void *p1, const void *p2)
     693                 :            : {
     694                 :            :         int res;
     695                 :            : 
     696                 :          0 :         res = subsort_threads(g_current_sort_col[THREADS_TAB], p1, p2);
     697         [ #  # ]:          0 :         if (res == 0) {
     698                 :          0 :                 res = subsort_threads(g_current_sort_col2[THREADS_TAB], p1, p2);
     699                 :            :         }
     700                 :          0 :         return res;
     701                 :            : }
     702                 :            : 
     703                 :            : static void
     704                 :          0 : store_last_counters(uint64_t poller_id, uint64_t thread_id, uint64_t last_run_counter,
     705                 :            :                     uint64_t last_busy_counter)
     706                 :            : {
     707                 :            :         struct run_counter_history *history;
     708                 :            : 
     709         [ #  # ]:          0 :         TAILQ_FOREACH(history, &g_run_counter_history, link) {
     710   [ #  #  #  # ]:          0 :                 if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
     711                 :          0 :                         history->last_run_counter = last_run_counter;
     712                 :          0 :                         history->last_busy_counter = last_busy_counter;
     713                 :          0 :                         return;
     714                 :            :                 }
     715                 :            :         }
     716                 :            : 
     717                 :          0 :         history = calloc(1, sizeof(*history));
     718         [ #  # ]:          0 :         if (history == NULL) {
     719   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate a history object in store_last_counters.\n");
     720                 :          0 :                 return;
     721                 :            :         }
     722                 :          0 :         history->poller_id = poller_id;
     723                 :          0 :         history->thread_id = thread_id;
     724                 :          0 :         history->last_run_counter = last_run_counter;
     725                 :          0 :         history->last_busy_counter = last_busy_counter;
     726                 :            : 
     727                 :          0 :         TAILQ_INSERT_TAIL(&g_run_counter_history, history, link);
     728                 :            : }
     729                 :            : 
     730                 :            : static int
     731                 :          0 : get_thread_data(void)
     732                 :            : {
     733                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
     734                 :          0 :         struct rpc_thread_info thread_info[RPC_MAX_THREADS], *thread;
     735                 :            :         struct rpc_core_info *core_info;
     736                 :          0 :         uint64_t i, j, k, current_threads_count = 0;
     737                 :          0 :         int rc = 0;
     738                 :            : 
     739                 :          0 :         rc = rpc_send_req("thread_get_stats", &json_resp);
     740         [ #  # ]:          0 :         if (rc) {
     741                 :          0 :                 return rc;
     742                 :            :         }
     743                 :            : 
     744                 :            :         /* Decode json */
     745         [ #  # ]:          0 :         memset(thread_info, 0, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
     746         [ #  # ]:          0 :         if (rpc_decode_threads_array(json_resp->result, thread_info, &current_threads_count)) {
     747                 :          0 :                 rc = -EINVAL;
     748         [ #  # ]:          0 :                 for (i = 0; i < current_threads_count; i++) {
     749                 :          0 :                         free_rpc_threads_stats(&thread_info[i]);
     750                 :            :                 }
     751                 :          0 :                 goto end;
     752                 :            :         }
     753                 :            : 
     754         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
     755                 :            : 
     756                 :            :         /* This is to free allocated char arrays with old thread names */
     757         [ #  # ]:          0 :         for (i = 0; i < g_last_threads_count; i++) {
     758                 :          0 :                 free_rpc_threads_stats(&g_threads_info[i]);
     759                 :            :         }
     760                 :            : 
     761         [ #  # ]:          0 :         for (i = 0; i < current_threads_count; i++) {
     762         [ #  # ]:          0 :                 for (j = 0; j < g_last_threads_count; j++) {
     763         [ #  # ]:          0 :                         if (thread_info[i].id == g_threads_info[j].id) {
     764                 :          0 :                                 thread_info[i].last_busy = g_threads_info[j].busy;
     765                 :          0 :                                 thread_info[i].last_idle = g_threads_info[j].idle;
     766                 :            :                         }
     767                 :            :                 }
     768                 :            :         }
     769                 :          0 :         g_last_threads_count = current_threads_count;
     770                 :            : 
     771                 :          0 :         memcpy(g_threads_info, thread_info, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
     772                 :            : 
     773         [ #  # ]:          0 :         for (i = 0; i < g_last_threads_count; i++) {
     774                 :          0 :                 g_threads_info[i].core_num = -1;
     775                 :            :         }
     776                 :            : 
     777         [ #  # ]:          0 :         for (i = 0; i < g_last_cores_count; i++) {
     778                 :          0 :                 core_info = &g_cores_info[i];
     779                 :            : 
     780         [ #  # ]:          0 :                 for (j = 0; j < core_info->threads.threads_count; j++) {
     781         [ #  # ]:          0 :                         for (k = 0; k < g_last_threads_count; k++) {
     782                 :            :                                 /* For each thread on current core: check if it's ID also exists
     783                 :            :                                  * in g_thread_info data structure. If it does then assign current
     784                 :            :                                  * core's number to that thread, otherwise application state is inconsistent
     785                 :            :                                  * (e.g. scheduler is moving threads between cores). */
     786                 :          0 :                                 thread = &g_threads_info[k];
     787         [ #  # ]:          0 :                                 if (thread->id == core_info->threads.thread[j].id) {
     788                 :          0 :                                         thread->core_num = core_info->lcore;
     789                 :          0 :                                         thread->core_idx = i;
     790                 :          0 :                                         break;
     791                 :            :                                 }
     792                 :            :                         }
     793                 :            :                 }
     794                 :            :         }
     795                 :            : 
     796   [ #  #  #  # ]:          0 :         qsort(g_threads_info, g_last_threads_count, sizeof(struct rpc_thread_info), sort_threads);
     797                 :            : 
     798         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
     799                 :            : 
     800                 :          0 : end:
     801                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
     802                 :          0 :         return rc;
     803                 :            : }
     804                 :            : 
     805                 :            : static uint64_t
     806                 :          0 : get_last_run_counter(uint64_t poller_id, uint64_t thread_id)
     807                 :            : {
     808                 :            :         struct run_counter_history *history;
     809                 :            : 
     810         [ #  # ]:          0 :         TAILQ_FOREACH(history, &g_run_counter_history, link) {
     811   [ #  #  #  # ]:          0 :                 if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
     812                 :          0 :                         return history->last_run_counter;
     813                 :            :                 }
     814                 :            :         }
     815                 :            : 
     816                 :          0 :         return 0;
     817                 :            : }
     818                 :            : 
     819                 :            : static uint64_t
     820                 :          0 : get_last_busy_counter(uint64_t poller_id, uint64_t thread_id)
     821                 :            : {
     822                 :            :         struct run_counter_history *history;
     823                 :            : 
     824         [ #  # ]:          0 :         TAILQ_FOREACH(history, &g_run_counter_history, link) {
     825   [ #  #  #  # ]:          0 :                 if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
     826                 :          0 :                         return history->last_busy_counter;
     827                 :            :                 }
     828                 :            :         }
     829                 :            : 
     830                 :          0 :         return 0;
     831                 :            : }
     832                 :            : 
     833                 :            : static int
     834                 :          0 : subsort_pollers(enum column_pollers_type sort_column, const void *p1, const void *p2)
     835                 :            : {
     836                 :          0 :         const struct rpc_poller_info *poller1 = (struct rpc_poller_info *)p1;
     837                 :          0 :         const struct rpc_poller_info *poller2 = (struct rpc_poller_info *)p2;
     838                 :            :         uint64_t count1, count2;
     839                 :            :         uint64_t last_busy_counter1, last_busy_counter2;
     840                 :            : 
     841   [ #  #  #  #  :          0 :         switch (sort_column) {
                #  #  # ]
     842                 :          0 :         case COL_POLLERS_NAME:
     843   [ #  #  #  # ]:          0 :                 return strcmp(poller1->name, poller2->name);
     844                 :          0 :         case COL_POLLERS_TYPE:
     845                 :          0 :                 return poller1->type - poller2->type;
     846                 :          0 :         case COL_POLLERS_THREAD_NAME:
     847   [ #  #  #  # ]:          0 :                 return strcmp(poller1->thread_name, poller2->thread_name);
     848                 :          0 :         case COL_POLLERS_RUN_COUNTER:
     849   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     850                 :          0 :                         count1 = poller1->run_count - get_last_run_counter(poller1->id, poller1->thread_id);
     851                 :          0 :                         count2 = poller2->run_count - get_last_run_counter(poller2->id, poller2->thread_id);
     852                 :            :                 } else {
     853                 :          0 :                         count1 = poller1->run_count;
     854                 :          0 :                         count2 = poller2->run_count;
     855                 :            :                 }
     856                 :          0 :                 break;
     857                 :          0 :         case COL_POLLERS_PERIOD:
     858                 :          0 :                 count1 = poller1->period_ticks;
     859                 :          0 :                 count2 = poller2->period_ticks;
     860                 :          0 :                 break;
     861                 :          0 :         case COL_POLLERS_BUSY_COUNT:
     862                 :          0 :                 count1 = poller1->busy_count;
     863                 :          0 :                 count2 = poller2->busy_count;
     864   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     865                 :          0 :                         last_busy_counter1 = get_last_busy_counter(poller1->id, poller1->thread_id);
     866                 :          0 :                         last_busy_counter2 = get_last_busy_counter(poller2->id, poller2->thread_id);
     867         [ #  # ]:          0 :                         if (count1 > last_busy_counter1) {
     868                 :          0 :                                 count1 -= last_busy_counter1;
     869                 :            :                         }
     870         [ #  # ]:          0 :                         if (count2 > last_busy_counter2) {
     871                 :          0 :                                 count2 -= last_busy_counter2;
     872                 :            :                         }
     873                 :            :                 }
     874                 :          0 :                 break;
     875                 :          0 :         case COL_POLLERS_NONE:
     876                 :            :         default:
     877                 :          0 :                 return 0;
     878                 :            :         }
     879                 :            : 
     880         [ #  # ]:          0 :         if (count2 > count1) {
     881                 :          0 :                 return 1;
     882         [ #  # ]:          0 :         } else if (count2 < count1) {
     883                 :          0 :                 return -1;
     884                 :            :         } else {
     885                 :          0 :                 return 0;
     886                 :            :         }
     887                 :            : }
     888                 :            : 
     889                 :            : static int
     890                 :          0 : sort_pollers(const void *p1, const void *p2)
     891                 :            : {
     892                 :            :         int rc;
     893                 :            : 
     894                 :          0 :         rc = subsort_pollers(g_current_sort_col[POLLERS_TAB], p1, p2);
     895         [ #  # ]:          0 :         if (rc == 0) {
     896                 :          0 :                 rc = subsort_pollers(g_current_sort_col2[POLLERS_TAB], p1, p2);
     897                 :            :         }
     898                 :          0 :         return rc;
     899                 :            : }
     900                 :            : 
     901                 :            : static int
     902                 :          0 : get_pollers_data(void)
     903                 :            : {
     904                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
     905                 :          0 :         int rc = 0;
     906                 :          0 :         uint64_t i = 0;
     907                 :          0 :         uint32_t current_pollers_count;
     908                 :          0 :         struct rpc_poller_info pollers_info[RPC_MAX_POLLERS];
     909                 :            : 
     910                 :          0 :         rc = rpc_send_req("thread_get_pollers", &json_resp);
     911         [ #  # ]:          0 :         if (rc) {
     912                 :          0 :                 return rc;
     913                 :            :         }
     914                 :            : 
     915                 :            :         /* Decode json */
     916         [ #  # ]:          0 :         memset(&pollers_info, 0, sizeof(pollers_info));
     917         [ #  # ]:          0 :         if (rpc_decode_pollers_threads_array(json_resp->result, pollers_info, &current_pollers_count)) {
     918                 :          0 :                 rc = -EINVAL;
     919         [ #  # ]:          0 :                 for (i = 0; i < current_pollers_count; i++) {
     920                 :          0 :                         free_rpc_poller(&pollers_info[i]);
     921                 :            :                 }
     922                 :          0 :                 goto end;
     923                 :            :         }
     924                 :            : 
     925         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
     926                 :            : 
     927                 :            :         /* Save last run counter of each poller before updating g_pollers_stats. */
     928         [ #  # ]:          0 :         for (i = 0; i < g_last_pollers_count; i++) {
     929                 :          0 :                 store_last_counters(g_pollers_info[i].id, g_pollers_info[i].thread_id,
     930                 :          0 :                                     g_pollers_info[i].run_count, g_pollers_info[i].busy_count);
     931                 :            :         }
     932                 :            : 
     933                 :            :         /* Free old pollers values before allocating memory for new ones */
     934         [ #  # ]:          0 :         for (i = 0; i < g_last_pollers_count; i++) {
     935                 :          0 :                 free_rpc_poller(&g_pollers_info[i]);
     936                 :            :         }
     937                 :            : 
     938                 :          0 :         g_last_pollers_count = current_pollers_count;
     939                 :            : 
     940   [ #  #  #  # ]:          0 :         qsort(&pollers_info, g_last_pollers_count, sizeof(struct rpc_poller_info), sort_pollers);
     941                 :            : 
     942   [ #  #  #  # ]:          0 :         memcpy(&g_pollers_info, &pollers_info, sizeof(struct rpc_poller_info) * g_last_pollers_count);
     943                 :            : 
     944         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
     945                 :            : 
     946                 :          0 : end:
     947                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
     948                 :          0 :         return rc;
     949                 :            : }
     950                 :            : 
     951                 :            : static int
     952                 :          0 : subsort_cores(enum column_cores_type sort_column, const void *p1, const void *p2)
     953                 :            : {
     954                 :          0 :         const struct rpc_core_info core_info1 = *(struct rpc_core_info *)p1;
     955                 :          0 :         const struct rpc_core_info core_info2 = *(struct rpc_core_info *)p2;
     956                 :            :         uint64_t count1, count2;
     957                 :            : 
     958   [ #  #  #  #  :          0 :         switch (sort_column) {
             #  #  #  #  
                      # ]
     959                 :          0 :         case COL_CORES_CORE:
     960                 :          0 :                 count1 = core_info2.lcore;
     961                 :          0 :                 count2 = core_info1.lcore;
     962                 :          0 :                 break;
     963                 :          0 :         case COL_CORES_THREADS:
     964                 :          0 :                 count1 = core_info1.threads.threads_count;
     965                 :          0 :                 count2 = core_info2.threads.threads_count;
     966                 :          0 :                 break;
     967                 :          0 :         case COL_CORES_POLLERS:
     968                 :          0 :                 count1 = core_info1.pollers_count;
     969                 :          0 :                 count2 = core_info2.pollers_count;
     970                 :          0 :                 break;
     971                 :          0 :         case COL_CORES_IDLE_TIME:
     972   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     973                 :          0 :                         count1 = core_info1.last_idle - core_info1.idle;
     974                 :          0 :                         count2 = core_info2.last_idle - core_info2.idle;
     975                 :            :                 } else {
     976                 :          0 :                         count1 = core_info1.idle;
     977                 :          0 :                         count2 = core_info2.idle;
     978                 :            :                 }
     979                 :          0 :                 break;
     980                 :          0 :         case COL_CORES_BUSY_TIME:
     981   [ #  #  #  # ]:          0 :                 if (g_interval_data) {
     982                 :          0 :                         count1 = core_info1.last_busy - core_info1.busy;
     983                 :          0 :                         count2 = core_info2.last_busy - core_info2.busy;
     984                 :            :                 } else {
     985                 :          0 :                         count1 = core_info1.busy;
     986                 :          0 :                         count2 = core_info2.busy;
     987                 :            :                 }
     988                 :          0 :                 break;
     989                 :          0 :         case COL_CORES_CORE_FREQ:
     990                 :          0 :                 count1 = core_info1.core_freq;
     991                 :          0 :                 count2 = core_info2.core_freq;
     992                 :          0 :                 break;
     993                 :          0 :         case COL_CORES_INTR:
     994         [ #  # ]:          0 :                 count1 = core_info1.in_interrupt;
     995         [ #  # ]:          0 :                 count2 = core_info2.in_interrupt;
     996                 :          0 :                 break;
     997                 :          0 :         case COL_CORES_BUSY_PCT:
     998                 :          0 :                 count1 = get_cpu_usage(core_info1.last_busy - core_info1.busy,
     999                 :          0 :                                        core_info1.last_idle - core_info1.idle);
    1000                 :          0 :                 count2 = get_cpu_usage(core_info2.last_busy - core_info2.busy,
    1001                 :          0 :                                        core_info2.last_idle - core_info2.idle);
    1002                 :          0 :                 break;
    1003                 :          0 :         case COL_CORES_NONE:
    1004                 :            :         default:
    1005                 :          0 :                 return 0;
    1006                 :            :         }
    1007                 :            : 
    1008         [ #  # ]:          0 :         if (count2 > count1) {
    1009                 :          0 :                 return 1;
    1010         [ #  # ]:          0 :         } else if (count2 < count1) {
    1011                 :          0 :                 return -1;
    1012                 :            :         } else {
    1013                 :          0 :                 return 0;
    1014                 :            :         }
    1015                 :            : }
    1016                 :            : 
    1017                 :            : static int
    1018                 :          0 : sort_cores(const void *p1, const void *p2)
    1019                 :            : {
    1020                 :            :         int rc;
    1021                 :            : 
    1022                 :          0 :         rc = subsort_cores(g_current_sort_col[CORES_TAB], p1, p2);
    1023         [ #  # ]:          0 :         if (rc == 0) {
    1024                 :          0 :                 return subsort_cores(g_current_sort_col[CORES_TAB], p1, p2);
    1025                 :            :         }
    1026                 :          0 :         return rc;
    1027                 :            : }
    1028                 :            : 
    1029                 :            : static int
    1030                 :          0 : get_cores_data(void)
    1031                 :            : {
    1032                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
    1033                 :            :         struct rpc_core_info *core_info;
    1034                 :            :         uint64_t i, j, k;
    1035                 :          0 :         uint32_t current_cores_count;
    1036                 :          0 :         struct rpc_core_info cores_info[RPC_MAX_CORES];
    1037                 :          0 :         int rc = 0;
    1038                 :            : 
    1039                 :          0 :         rc = rpc_send_req("framework_get_reactors", &json_resp);
    1040         [ #  # ]:          0 :         if (rc) {
    1041                 :          0 :                 return rc;
    1042                 :            :         }
    1043                 :            : 
    1044                 :            :         /* Decode json */
    1045         [ #  # ]:          0 :         memset(cores_info, 0, sizeof(struct rpc_core_info) * RPC_MAX_CORES);
    1046         [ #  # ]:          0 :         if (rpc_decode_cores_array(json_resp->result, cores_info, &current_cores_count)) {
    1047                 :          0 :                 rc = -EINVAL;
    1048                 :          0 :                 goto end;
    1049                 :            :         }
    1050                 :            : 
    1051         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    1052         [ #  # ]:          0 :         for (i = 0; i < current_cores_count; i++) {
    1053         [ #  # ]:          0 :                 for (j = 0; j < g_last_cores_count; j++) {
    1054         [ #  # ]:          0 :                         if (cores_info[i].lcore == g_cores_info[j].lcore) {
    1055                 :          0 :                                 cores_info[i].last_busy = g_cores_info[j].busy;
    1056                 :          0 :                                 cores_info[i].last_idle = g_cores_info[j].idle;
    1057                 :          0 :                                 cores_info[i].last_irq = g_cores_info[j].irq;
    1058                 :          0 :                                 cores_info[i].last_sys = g_cores_info[j].sys;
    1059                 :          0 :                                 cores_info[i].last_usr = g_cores_info[j].usr;
    1060                 :            :                         }
    1061                 :            :                 }
    1062                 :            :         }
    1063                 :            : 
    1064                 :            :         /* Free old cores values before allocating memory for new ones */
    1065                 :          0 :         free_rpc_core_info(g_cores_info, current_cores_count);
    1066   [ #  #  #  # ]:          0 :         memcpy(g_cores_info, cores_info, sizeof(struct rpc_core_info) * current_cores_count);
    1067                 :            : 
    1068         [ #  # ]:          0 :         for (i = 0; i < g_last_cores_count; i++) {
    1069                 :          0 :                 core_info = &g_cores_info[i];
    1070                 :            : 
    1071                 :          0 :                 core_info->threads.thread = cores_info[i].threads.thread;
    1072                 :            : 
    1073         [ #  # ]:          0 :                 for (j = 0; j < core_info->threads.threads_count; j++) {
    1074                 :          0 :                         memcpy(&core_info->threads.thread[j], &cores_info[i].threads.thread[j],
    1075                 :            :                                sizeof(struct rpc_core_thread_info));
    1076         [ #  # ]:          0 :                         for (k = 0; k < g_last_threads_count; k++) {
    1077         [ #  # ]:          0 :                                 if (core_info->threads.thread[j].id == g_threads_info[k].id) {
    1078                 :          0 :                                         g_threads_info[k].core_num = core_info->lcore;
    1079                 :            :                                         /* Do not consider threads which changed cores when issuing
    1080                 :            :                                          * RPCs to get_core_data and get_thread_data and threads
    1081                 :            :                                          * not currently assigned to this core. */
    1082                 :          0 :                                         core_info->pollers_count += g_threads_info[k].active_pollers_count +
    1083                 :          0 :                                                                     g_threads_info[k].timed_pollers_count +
    1084                 :          0 :                                                                     g_threads_info[k].paused_pollers_count;
    1085                 :            :                                 }
    1086                 :            :                         }
    1087                 :            :                 }
    1088                 :            :         }
    1089                 :            : 
    1090                 :          0 :         g_last_cores_count = current_cores_count;
    1091                 :            : 
    1092   [ #  #  #  # ]:          0 :         qsort(&g_cores_info, g_last_cores_count, sizeof(struct rpc_core_info), sort_cores);
    1093                 :            : 
    1094                 :          0 : end:
    1095         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    1096                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
    1097                 :          0 :         return rc;
    1098                 :            : }
    1099                 :            : 
    1100                 :            : static int
    1101                 :          0 : get_scheduler_data(void)
    1102                 :            : {
    1103                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
    1104                 :          0 :         struct rpc_scheduler scheduler_info;
    1105                 :          0 :         int rc = 0;
    1106                 :            : 
    1107                 :          0 :         rc = rpc_send_req("framework_get_scheduler", &json_resp);
    1108         [ #  # ]:          0 :         if (rc) {
    1109                 :          0 :                 return rc;
    1110                 :            :         }
    1111                 :            : 
    1112         [ #  # ]:          0 :         memset(&scheduler_info, 0, sizeof(scheduler_info));
    1113         [ #  # ]:          0 :         if (spdk_json_decode_object_relaxed(json_resp->result, rpc_scheduler_decoders,
    1114                 :            :                                             SPDK_COUNTOF(rpc_scheduler_decoders), &scheduler_info)) {
    1115                 :          0 :                 rc = -EINVAL;
    1116                 :            :         } else {
    1117         [ #  # ]:          0 :                 pthread_mutex_lock(&g_thread_lock);
    1118                 :            : 
    1119                 :          0 :                 free_rpc_scheduler(&g_scheduler_info);
    1120                 :            : 
    1121                 :          0 :                 memcpy(&g_scheduler_info, &scheduler_info, sizeof(struct rpc_scheduler));
    1122         [ #  # ]:          0 :                 pthread_mutex_unlock(&g_thread_lock);
    1123                 :            :         }
    1124                 :            : 
    1125                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
    1126                 :          0 :         return rc;
    1127                 :            : }
    1128                 :            : 
    1129                 :            : enum str_alignment {
    1130                 :            :         ALIGN_LEFT,
    1131                 :            :         ALIGN_RIGHT,
    1132                 :            : };
    1133                 :            : 
    1134                 :            : static void
    1135                 :          0 : print_max_len(WINDOW *win, int row, uint16_t col, uint16_t max_len, enum str_alignment alignment,
    1136                 :            :               const char *string)
    1137                 :            : {
    1138                 :          0 :         const char dots[] = "...";
    1139                 :          0 :         int DOTS_STR_LEN = sizeof(dots) / sizeof(dots[0]);
    1140                 :          0 :         char tmp_str[MAX_STRING_LEN];
    1141                 :            :         int len, max_col, max_str, cmp_len;
    1142                 :            :         int max_row;
    1143                 :            : 
    1144         [ #  # ]:          0 :         len = strlen(string);
    1145   [ #  #  #  # ]:          0 :         getmaxyx(win, max_row, max_col);
    1146                 :            : 
    1147         [ #  # ]:          0 :         if (row > max_row) {
    1148                 :            :                 /* We are in a process of resizing and this may happen */
    1149                 :          0 :                 return;
    1150                 :            :         }
    1151                 :            : 
    1152   [ #  #  #  # ]:          0 :         if (max_len != 0 && col + max_len < max_col) {
    1153                 :          0 :                 max_col = col + max_len;
    1154                 :            :         }
    1155                 :            : 
    1156                 :          0 :         max_str = max_col - col;
    1157                 :            : 
    1158         [ #  # ]:          0 :         if (max_str <= DOTS_STR_LEN + 1) {
    1159                 :            :                 /* No space to print anything, but we have to let a user know about it */
    1160                 :          0 :                 mvwprintw(win, row, max_col - DOTS_STR_LEN - 1, "...");
    1161                 :          0 :                 wnoutrefresh(win);
    1162                 :          0 :                 return;
    1163                 :            :         }
    1164                 :            : 
    1165         [ #  # ]:          0 :         if (max_len) {
    1166         [ #  # ]:          0 :                 if (alignment == ALIGN_LEFT) {
    1167                 :          0 :                         snprintf(tmp_str, max_str, "%s%*c", string, max_len - len - 1, ' ');
    1168                 :            :                 } else {
    1169                 :          0 :                         snprintf(tmp_str, max_str, "%*c%s", max_len - len - 1, ' ', string);
    1170                 :            :                 }
    1171                 :          0 :                 cmp_len = max_len - 1;
    1172                 :            :         } else {
    1173                 :          0 :                 snprintf(tmp_str, max_str, "%s", string);
    1174                 :          0 :                 cmp_len = len;
    1175                 :            :         }
    1176                 :            : 
    1177         [ #  # ]:          0 :         if (col + cmp_len > max_col - 1) {
    1178                 :          0 :                 snprintf(&tmp_str[max_str - DOTS_STR_LEN - 2], DOTS_STR_LEN, "%s", dots);
    1179                 :            :         }
    1180                 :            : 
    1181                 :          0 :         mvwprintw(win, row, col, "%s", tmp_str);
    1182                 :            : 
    1183                 :          0 :         wnoutrefresh(win);
    1184                 :            : }
    1185                 :            : 
    1186                 :            : static void
    1187                 :          0 : draw_menu_win(void)
    1188                 :            : {
    1189                 :          0 :         wbkgd(g_menu_win, COLOR_PAIR(2));
    1190                 :          0 :         box(g_menu_win, 0, 0);
    1191                 :          0 :         print_max_len(g_menu_win, 1, 1, 0, ALIGN_LEFT,
    1192                 :            :                       "  [q] Quit  |  [1-3][Tab] Switch tab  |  [PgUp] Previous page  |  [PgDown] Next page  |  [Enter] Item details  |  [h] Help");
    1193                 :          0 : }
    1194                 :            : 
    1195                 :            : static void
    1196                 :          0 : draw_tab_win(enum tabs tab)
    1197                 :            : {
    1198                 :            :         uint16_t col;
    1199                 :          0 :         uint8_t white_spaces = TABS_SPACING * NUMBER_OF_TABS;
    1200                 :            : 
    1201                 :          0 :         wbkgd(g_tab_win[tab], COLOR_PAIR(10));
    1202                 :          0 :         box(g_tab_win[tab], 0, 0);
    1203                 :            : 
    1204         [ #  # ]:          0 :         col = ((g_max_col - white_spaces) / NUMBER_OF_TABS / 2) - (strlen(g_tab_title[tab]) / 2) -
    1205                 :            :               TABS_SPACING;
    1206                 :          0 :         print_max_len(g_tab_win[tab], 1, col, 0, ALIGN_LEFT, g_tab_title[tab]);
    1207                 :          0 : }
    1208                 :            : 
    1209                 :            : static void
    1210                 :          0 : draw_tabs(enum tabs tab_index, uint8_t sort_col, uint8_t sort_col2)
    1211                 :            : {
    1212                 :          0 :         struct col_desc *col_desc = g_col_desc[tab_index];
    1213                 :          0 :         WINDOW *tab = g_tabs[tab_index];
    1214                 :            :         int i, j;
    1215                 :            :         uint16_t offset, draw_offset;
    1216                 :          0 :         uint16_t tab_height = g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 3;
    1217                 :            : 
    1218         [ #  # ]:          0 :         for (i = 0; col_desc[i].name != NULL; i++) {
    1219   [ #  #  #  # ]:          0 :                 if (col_desc[i].disabled) {
    1220                 :          0 :                         continue;
    1221                 :            :                 }
    1222                 :            : 
    1223                 :          0 :                 offset = 1;
    1224         [ #  # ]:          0 :                 for (j = i; j != 0; j--) {
    1225   [ #  #  #  # ]:          0 :                         if (!col_desc[j - 1].disabled) {
    1226                 :          0 :                                 offset += col_desc[j - 1].max_data_string;
    1227                 :          0 :                                 offset += col_desc[j - 1].name_len % 2 + 1;
    1228                 :            :                         }
    1229                 :            :                 }
    1230                 :            : 
    1231                 :          0 :                 draw_offset = offset + (col_desc[i].max_data_string / 2) - (col_desc[i].name_len / 2);
    1232                 :            : 
    1233         [ #  # ]:          0 :                 if (i == sort_col) {
    1234                 :          0 :                         wattron(tab, COLOR_PAIR(4));
    1235                 :          0 :                         print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
    1236                 :          0 :                         wattroff(tab, COLOR_PAIR(4));
    1237         [ #  # ]:          0 :                 } else if (i == sort_col2) {
    1238                 :          0 :                         wattron(tab, COLOR_PAIR(3));
    1239                 :          0 :                         print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
    1240                 :          0 :                         wattroff(tab, COLOR_PAIR(3));
    1241                 :            :                 } else {
    1242                 :          0 :                         print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
    1243                 :            :                 }
    1244                 :            : 
    1245         [ #  # ]:          0 :                 if (offset != 1) {
    1246                 :          0 :                         print_max_len(tab, 1, offset - 1, 0, ALIGN_LEFT, "|");
    1247                 :            :                 }
    1248                 :            :         }
    1249                 :            : 
    1250                 :          0 :         print_max_len(tab, 2, 1, 0, ALIGN_LEFT, ""); /* Move to next line */
    1251                 :          0 :         whline(tab, ACS_HLINE, g_max_col - 2);
    1252                 :            : 
    1253                 :            :         /* Border lines */
    1254         [ #  # ]:          0 :         mvwhline(tab, 0, 1, ACS_HLINE, g_max_col - 2);
    1255         [ #  # ]:          0 :         mvwhline(tab, tab_height, 1, ACS_HLINE, g_max_col - 2);
    1256                 :            : 
    1257                 :          0 :         wrefresh(tab);
    1258                 :          0 : }
    1259                 :            : 
    1260                 :            : static void
    1261                 :          0 : resize_interface(enum tabs tab)
    1262                 :            : {
    1263                 :            :         int i;
    1264                 :            : 
    1265                 :          0 :         clear();
    1266                 :          0 :         wclear(g_menu_win);
    1267                 :          0 :         mvwin(g_menu_win, g_max_row - MENU_WIN_SPACING, MENU_WIN_LOCATION_COL);
    1268                 :          0 :         wresize(g_menu_win, MENU_WIN_HEIGHT, g_max_col);
    1269                 :          0 :         draw_menu_win();
    1270                 :            : 
    1271         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    1272                 :          0 :                 wclear(g_tabs[i]);
    1273                 :          0 :                 wresize(g_tabs[i], g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 2, g_max_col);
    1274                 :          0 :                 mvwin(g_tabs[i], TABS_LOCATION_ROW, TABS_LOCATION_COL);
    1275                 :            :         }
    1276                 :            : 
    1277                 :          0 :         draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
    1278                 :            : 
    1279         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    1280                 :          0 :                 wclear(g_tab_win[i]);
    1281                 :          0 :                 wresize(g_tab_win[i], TAB_WIN_HEIGHT,
    1282                 :          0 :                         (g_max_col - (TABS_SPACING * NUMBER_OF_TABS)) / NUMBER_OF_TABS);
    1283                 :          0 :                 mvwin(g_tab_win[i], TAB_WIN_LOCATION_ROW, 1 + (g_max_col / NUMBER_OF_TABS) * i);
    1284                 :          0 :                 draw_tab_win(i);
    1285                 :            :         }
    1286                 :            : 
    1287                 :          0 :         update_panels();
    1288                 :          0 :         doupdate();
    1289                 :          0 : }
    1290                 :            : 
    1291                 :            : static void
    1292                 :          0 : switch_tab(enum tabs tab)
    1293                 :            : {
    1294                 :          0 :         wclear(g_tabs[tab]);
    1295                 :          0 :         draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
    1296                 :          0 :         top_panel(g_panels[tab]);
    1297                 :          0 :         update_panels();
    1298                 :          0 :         doupdate();
    1299                 :          0 : }
    1300                 :            : 
    1301                 :            : static void
    1302                 :          0 : get_time_str(uint64_t ticks, char *time_str)
    1303                 :            : {
    1304                 :            :         uint64_t time;
    1305                 :            : 
    1306         [ #  # ]:          0 :         time = ticks * SPDK_SEC_TO_USEC / g_tick_rate;
    1307         [ #  # ]:          0 :         snprintf(time_str, MAX_TIME_STR_LEN, "%" PRIu64, time);
    1308                 :          0 : }
    1309                 :            : 
    1310                 :            : static void
    1311                 :          0 : draw_row_background(uint8_t item_index, uint8_t tab)
    1312                 :            : {
    1313                 :            :         int k;
    1314                 :            : 
    1315         [ #  # ]:          0 :         if (item_index == g_selected_row) {
    1316                 :          0 :                 wattron(g_tabs[tab], COLOR_PAIR(2));
    1317                 :            :         }
    1318         [ #  # ]:          0 :         for (k = 1; k < g_max_col - 1; k++) {
    1319                 :          0 :                 mvwprintw(g_tabs[tab], TABS_DATA_START_ROW + item_index, k, " ");
    1320                 :            :         }
    1321                 :          0 : }
    1322                 :            : 
    1323                 :            : static void
    1324                 :          0 : get_cpu_usage_str(uint64_t busy_ticks, uint64_t total_ticks, char *cpu_str)
    1325                 :            : {
    1326         [ #  # ]:          0 :         if (total_ticks > 0) {
    1327                 :          0 :                 snprintf(cpu_str, MAX_FLOAT_STR_LEN, "%.2f",
    1328         [ #  # ]:          0 :                          (double)(busy_ticks) * 100 / (double)(total_ticks));
    1329                 :            :         } else {
    1330                 :          0 :                 cpu_str[0] = '\0';
    1331                 :            :         }
    1332                 :          0 : }
    1333                 :            : 
    1334                 :            : static void
    1335                 :          0 : draw_thread_tab_row(uint64_t current_row, uint8_t item_index)
    1336                 :            : {
    1337                 :          0 :         struct col_desc *col_desc = g_col_desc[THREADS_TAB];
    1338                 :          0 :         uint16_t col = TABS_DATA_START_COL;
    1339                 :          0 :         int core_idx, color_attr = COLOR_PAIR(6);
    1340                 :          0 :         char pollers_number[MAX_POLLER_TYPE_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN],
    1341                 :          0 :              busy_time[MAX_TIME_STR_LEN], core_str[MAX_CORE_MASK_STR_LEN],
    1342                 :          0 :              cpu_usage[MAX_FLOAT_STR_LEN], *status_str;
    1343                 :            : 
    1344   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_NAME].disabled) {
    1345                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
    1346                 :          0 :                               col_desc[COL_THREADS_NAME].max_data_string, ALIGN_LEFT, g_threads_info[current_row].name);
    1347                 :          0 :                 col += col_desc[COL_THREADS_NAME].max_data_string;
    1348                 :            :         }
    1349                 :            : 
    1350   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_CORE].disabled) {
    1351         [ #  # ]:          0 :                 snprintf(core_str, MAX_CORE_STR_LEN, "%d", g_threads_info[current_row].core_num);
    1352                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
    1353                 :          0 :                               col, col_desc[COL_THREADS_CORE].max_data_string, ALIGN_RIGHT, core_str);
    1354                 :          0 :                 col += col_desc[COL_THREADS_CORE].max_data_string + 2;
    1355                 :            :         }
    1356                 :            : 
    1357   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_ACTIVE_POLLERS].disabled) {
    1358         [ #  # ]:          0 :                 snprintf(pollers_number, MAX_POLLER_TYPE_COUNT_STR_LEN, "%ld",
    1359                 :          0 :                          g_threads_info[current_row].active_pollers_count);
    1360                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
    1361                 :          0 :                               col + (col_desc[COL_THREADS_ACTIVE_POLLERS].name_len / 2),
    1362                 :          0 :                               col_desc[COL_THREADS_ACTIVE_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
    1363                 :          0 :                 col += col_desc[COL_THREADS_ACTIVE_POLLERS].max_data_string + 2;
    1364                 :            :         }
    1365                 :            : 
    1366   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_TIMED_POLLERS].disabled) {
    1367         [ #  # ]:          0 :                 snprintf(pollers_number, MAX_POLLER_TYPE_COUNT_STR_LEN, "%ld",
    1368                 :          0 :                          g_threads_info[current_row].timed_pollers_count);
    1369                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
    1370                 :          0 :                               col + (col_desc[COL_THREADS_TIMED_POLLERS].name_len / 2),
    1371                 :          0 :                               col_desc[COL_THREADS_TIMED_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
    1372                 :          0 :                 col += col_desc[COL_THREADS_TIMED_POLLERS].max_data_string + 1;
    1373                 :            :         }
    1374                 :            : 
    1375   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_PAUSED_POLLERS].disabled) {
    1376         [ #  # ]:          0 :                 snprintf(pollers_number, MAX_POLLER_TYPE_COUNT_STR_LEN, "%ld",
    1377                 :          0 :                          g_threads_info[current_row].paused_pollers_count);
    1378                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
    1379                 :          0 :                               col + (col_desc[COL_THREADS_PAUSED_POLLERS].name_len / 2),
    1380                 :          0 :                               col_desc[COL_THREADS_PAUSED_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
    1381                 :          0 :                 col += col_desc[COL_THREADS_PAUSED_POLLERS].max_data_string + 2;
    1382                 :            :         }
    1383                 :            : 
    1384                 :          0 :         uint64_t idle_period = g_threads_info[current_row].idle - g_threads_info[current_row].last_idle;
    1385                 :          0 :         uint64_t busy_period = g_threads_info[current_row].busy - g_threads_info[current_row].last_busy;
    1386   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_IDLE_TIME].disabled) {
    1387   [ #  #  #  # ]:          0 :                 if (g_interval_data == true) {
    1388                 :          0 :                         get_time_str(idle_period, idle_time);
    1389                 :            :                 } else {
    1390                 :          0 :                         get_time_str(g_threads_info[current_row].idle, idle_time);
    1391                 :            :                 }
    1392                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
    1393                 :          0 :                               col_desc[COL_THREADS_IDLE_TIME].max_data_string, ALIGN_RIGHT, idle_time);
    1394                 :          0 :                 col += col_desc[COL_THREADS_IDLE_TIME].max_data_string;
    1395                 :            :         }
    1396                 :            : 
    1397   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_BUSY_TIME].disabled) {
    1398   [ #  #  #  # ]:          0 :                 if (g_interval_data == true) {
    1399                 :          0 :                         get_time_str(busy_period, busy_time);
    1400                 :            :                 } else {
    1401                 :          0 :                         get_time_str(g_threads_info[current_row].busy, busy_time);
    1402                 :            :                 }
    1403                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
    1404                 :          0 :                               col_desc[COL_THREADS_BUSY_TIME].max_data_string, ALIGN_RIGHT, busy_time);
    1405                 :          0 :                 col += col_desc[COL_THREADS_BUSY_TIME].max_data_string + 3;
    1406                 :            :         }
    1407                 :            : 
    1408   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_CPU_USAGE].disabled) {
    1409                 :          0 :                 core_idx = g_threads_info[current_row].core_idx;
    1410   [ #  #  #  # ]:          0 :                 if (core_idx >= 0 && core_idx < RPC_MAX_CORES) {
    1411                 :          0 :                         uint64_t core_busy_period = g_cores_info[core_idx].busy - g_cores_info[core_idx].last_busy;
    1412                 :          0 :                         uint64_t core_idle_period = g_cores_info[core_idx].idle - g_cores_info[core_idx].last_idle;
    1413                 :          0 :                         get_cpu_usage_str(busy_period, core_busy_period + core_idle_period, cpu_usage);
    1414                 :            :                 } else {
    1415         [ #  # ]:          0 :                         snprintf(cpu_usage, sizeof(cpu_usage), "n/a");
    1416                 :            :                 }
    1417                 :            : 
    1418                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
    1419                 :          0 :                               col_desc[COL_THREADS_CPU_USAGE].max_data_string, ALIGN_RIGHT, cpu_usage);
    1420                 :          0 :                 col += col_desc[COL_THREADS_CPU_USAGE].max_data_string + 2;
    1421                 :            :         }
    1422                 :            : 
    1423   [ #  #  #  # ]:          0 :         if (!col_desc[COL_THREADS_STATUS].disabled) {
    1424         [ #  # ]:          0 :                 if (busy_period > idle_period) {
    1425         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1426                 :          0 :                                 color_attr = COLOR_PAIR(6);
    1427                 :            :                         } else {
    1428                 :          0 :                                 color_attr = COLOR_PAIR(8);
    1429                 :            :                         }
    1430                 :          0 :                         status_str = "Busy";
    1431                 :            :                 } else {
    1432         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1433                 :          0 :                                 color_attr = COLOR_PAIR(7);
    1434                 :            :                         } else {
    1435                 :          0 :                                 color_attr = COLOR_PAIR(9);
    1436                 :            :                         }
    1437                 :          0 :                         status_str = "Idle";
    1438                 :            :                 }
    1439                 :          0 :                 wattron(g_tabs[THREADS_TAB], color_attr);
    1440                 :          0 :                 print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
    1441                 :          0 :                               col_desc[COL_THREADS_STATUS].max_data_string, ALIGN_RIGHT, status_str);
    1442                 :          0 :                 wattroff(g_tabs[THREADS_TAB], color_attr);
    1443                 :            :         }
    1444                 :          0 : }
    1445                 :            : 
    1446                 :            : static uint8_t
    1447                 :          0 : refresh_threads_tab(uint8_t current_page)
    1448                 :            : {
    1449                 :            :         uint64_t i, j, threads_count;
    1450                 :          0 :         uint16_t empty_col = 0;
    1451                 :            :         uint8_t max_pages, item_index;
    1452                 :            : 
    1453                 :          0 :         threads_count = g_last_threads_count;
    1454                 :            : 
    1455         [ #  # ]:          0 :         max_pages = (threads_count + g_max_data_rows - 1) / g_max_data_rows;
    1456                 :            : 
    1457                 :          0 :         for (i = current_page * g_max_data_rows;
    1458         [ #  # ]:          0 :              i < (uint64_t)((current_page + 1) * g_max_data_rows);
    1459                 :          0 :              i++) {
    1460                 :          0 :                 item_index = i - (current_page * g_max_data_rows);
    1461                 :            : 
    1462                 :            :                 /* When number of threads decreases, this will print spaces in places
    1463                 :            :                  * where non existent threads were previously displayed. */
    1464         [ #  # ]:          0 :                 if (i >= threads_count) {
    1465         [ #  # ]:          0 :                         for (j = 1; j < (uint64_t)g_max_col - 1; j++) {
    1466                 :          0 :                                 mvwprintw(g_tabs[THREADS_TAB], item_index + TABS_DATA_START_ROW, j, " ");
    1467                 :            :                         }
    1468                 :            : 
    1469                 :          0 :                         empty_col++;
    1470                 :          0 :                         continue;
    1471                 :            :                 }
    1472                 :            : 
    1473                 :          0 :                 draw_row_background(item_index, THREADS_TAB);
    1474                 :          0 :                 draw_thread_tab_row(i, item_index);
    1475                 :            : 
    1476         [ #  # ]:          0 :                 if (item_index == g_selected_row) {
    1477                 :          0 :                         wattroff(g_tabs[THREADS_TAB], COLOR_PAIR(2));
    1478                 :            :                 }
    1479                 :            :         }
    1480                 :            : 
    1481                 :          0 :         g_max_selected_row = i - current_page * g_max_data_rows - 1 - empty_col;
    1482                 :            : 
    1483                 :          0 :         return max_pages;
    1484                 :            : }
    1485                 :            : 
    1486                 :            : static void
    1487                 :          0 : draw_poller_tab_row(uint64_t current_row, uint8_t item_index)
    1488                 :            : {
    1489                 :          0 :         struct col_desc *col_desc = g_col_desc[POLLERS_TAB];
    1490                 :            :         uint64_t last_run_counter, last_busy_counter;
    1491                 :          0 :         uint16_t col = TABS_DATA_START_COL;
    1492                 :          0 :         char run_count[MAX_POLLER_RUN_COUNT], period_ticks[MAX_PERIOD_STR_LEN],
    1493                 :          0 :              status[MAX_POLLER_IND_STR_LEN];
    1494                 :            : 
    1495                 :          0 :         last_busy_counter = get_last_busy_counter(g_pollers_info[current_row].id,
    1496                 :          0 :                             g_pollers_info[current_row].thread_id);
    1497                 :            : 
    1498   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_NAME].disabled) {
    1499                 :          0 :                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col + 1,
    1500                 :          0 :                               col_desc[COL_POLLERS_NAME].max_data_string, ALIGN_LEFT, g_pollers_info[current_row].name);
    1501                 :          0 :                 col += col_desc[COL_POLLERS_NAME].max_data_string + 2;
    1502                 :            :         }
    1503                 :            : 
    1504   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_TYPE].disabled) {
    1505                 :          0 :                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1506                 :          0 :                               col_desc[COL_POLLERS_TYPE].max_data_string, ALIGN_LEFT,
    1507                 :          0 :                               poller_type_str[g_pollers_info[current_row].type]);
    1508                 :          0 :                 col += col_desc[COL_POLLERS_TYPE].max_data_string + 2;
    1509                 :            :         }
    1510                 :            : 
    1511   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_THREAD_NAME].disabled) {
    1512                 :          0 :                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1513                 :          0 :                               col_desc[COL_POLLERS_THREAD_NAME].max_data_string, ALIGN_LEFT,
    1514                 :          0 :                               g_pollers_info[current_row].thread_name);
    1515                 :          0 :                 col += col_desc[COL_POLLERS_THREAD_NAME].max_data_string + 1;
    1516                 :            :         }
    1517                 :            : 
    1518   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_RUN_COUNTER].disabled) {
    1519                 :          0 :                 last_run_counter = get_last_run_counter(g_pollers_info[current_row].id,
    1520                 :          0 :                                                         g_pollers_info[current_row].thread_id);
    1521   [ #  #  #  # ]:          0 :                 if (g_interval_data == true) {
    1522                 :          0 :                         snprintf(run_count, MAX_POLLER_RUN_COUNT, "%" PRIu64,
    1523         [ #  # ]:          0 :                                  g_pollers_info[current_row].run_count - last_run_counter);
    1524                 :            :                 } else {
    1525         [ #  # ]:          0 :                         snprintf(run_count, MAX_POLLER_RUN_COUNT, "%" PRIu64, g_pollers_info[current_row].run_count);
    1526                 :            :                 }
    1527                 :          0 :                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1528                 :          0 :                               col_desc[COL_POLLERS_RUN_COUNTER].max_data_string, ALIGN_RIGHT, run_count);
    1529                 :          0 :                 col += col_desc[COL_POLLERS_RUN_COUNTER].max_data_string;
    1530                 :            :         }
    1531                 :            : 
    1532   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_PERIOD].disabled) {
    1533         [ #  # ]:          0 :                 if (g_pollers_info[current_row].period_ticks != 0) {
    1534                 :          0 :                         get_time_str(g_pollers_info[current_row].period_ticks, period_ticks);
    1535                 :          0 :                         print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1536                 :          0 :                                       col_desc[COL_POLLERS_PERIOD].max_data_string, ALIGN_RIGHT, period_ticks);
    1537                 :            :                 }
    1538                 :          0 :                 col += col_desc[COL_POLLERS_PERIOD].max_data_string + 7;
    1539                 :            :         }
    1540                 :            : 
    1541   [ #  #  #  # ]:          0 :         if (!col_desc[COL_POLLERS_BUSY_COUNT].disabled) {
    1542         [ #  # ]:          0 :                 if (g_pollers_info[current_row].busy_count > last_busy_counter) {
    1543   [ #  #  #  # ]:          0 :                         if (g_interval_data == true) {
    1544                 :          0 :                                 snprintf(status, MAX_POLLER_IND_STR_LEN, "Busy (%" PRIu64 ")",
    1545         [ #  # ]:          0 :                                          g_pollers_info[current_row].busy_count - last_busy_counter);
    1546                 :            :                         } else {
    1547         [ #  # ]:          0 :                                 snprintf(status, MAX_POLLER_IND_STR_LEN, "Busy (%" PRIu64 ")",
    1548                 :          0 :                                          g_pollers_info[current_row].busy_count);
    1549                 :            :                         }
    1550                 :            : 
    1551         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1552                 :          0 :                                 wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(6));
    1553                 :          0 :                                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1554                 :          0 :                                               col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
    1555                 :          0 :                                 wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(6));
    1556                 :            :                         } else {
    1557                 :          0 :                                 wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(8));
    1558                 :          0 :                                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1559                 :          0 :                                               col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
    1560                 :          0 :                                 wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(8));
    1561                 :            :                         }
    1562                 :            :                 } else {
    1563   [ #  #  #  # ]:          0 :                         if (g_interval_data == true) {
    1564         [ #  # ]:          0 :                                 snprintf(status, MAX_POLLER_IND_STR_LEN, "%s", "Idle");
    1565                 :            :                         } else {
    1566         [ #  # ]:          0 :                                 snprintf(status, MAX_POLLER_IND_STR_LEN, "Idle (%" PRIu64 ")",
    1567                 :          0 :                                          g_pollers_info[current_row].busy_count);
    1568                 :            :                         }
    1569                 :            : 
    1570         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1571                 :          0 :                                 wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(7));
    1572                 :          0 :                                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1573                 :          0 :                                               col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
    1574                 :          0 :                                 wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(7));
    1575                 :            :                         } else {
    1576                 :          0 :                                 wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(9));
    1577                 :          0 :                                 print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
    1578                 :          0 :                                               col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
    1579                 :          0 :                                 wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(9));
    1580                 :            :                         }
    1581                 :            :                 }
    1582                 :            :         }
    1583                 :          0 : }
    1584                 :            : 
    1585                 :            : static uint8_t
    1586                 :          0 : refresh_pollers_tab(uint8_t current_page)
    1587                 :            : {
    1588                 :            :         uint64_t i, j;
    1589                 :          0 :         uint16_t empty_col = 0;
    1590                 :            :         uint8_t max_pages, item_index;
    1591                 :            : 
    1592         [ #  # ]:          0 :         max_pages = (g_last_pollers_count + g_max_data_rows - 1) / g_max_data_rows;
    1593                 :            : 
    1594                 :            :         /* Display info */
    1595                 :          0 :         for (i = current_page * g_max_data_rows;
    1596         [ #  # ]:          0 :              i < (uint64_t)((current_page + 1) * g_max_data_rows);
    1597                 :          0 :              i++) {
    1598                 :          0 :                 item_index = i - (current_page * g_max_data_rows);
    1599                 :            : 
    1600                 :            :                 /* When number of pollers decreases, this will print spaces in places
    1601                 :            :                  * where non existent pollers were previously displayed. */
    1602         [ #  # ]:          0 :                 if (i >= g_last_pollers_count) {
    1603         [ #  # ]:          0 :                         for (j = 1; j < (uint64_t)g_max_col - 1; j++) {
    1604                 :          0 :                                 mvwprintw(g_tabs[POLLERS_TAB], item_index + TABS_DATA_START_ROW, j, " ");
    1605                 :            :                         }
    1606                 :            : 
    1607                 :          0 :                         empty_col++;
    1608                 :          0 :                         continue;
    1609                 :            :                 }
    1610                 :            : 
    1611                 :          0 :                 draw_row_background(item_index, POLLERS_TAB);
    1612                 :          0 :                 draw_poller_tab_row(i, item_index);
    1613                 :            : 
    1614         [ #  # ]:          0 :                 if (item_index == g_selected_row) {
    1615                 :          0 :                         wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(2));
    1616                 :            :                 }
    1617                 :            :         }
    1618                 :            : 
    1619                 :          0 :         g_max_selected_row = i - current_page * g_max_data_rows - 1 - empty_col;
    1620                 :            : 
    1621                 :          0 :         return max_pages;
    1622                 :            : }
    1623                 :            : 
    1624                 :            : static void
    1625                 :          0 : draw_core_tab_row(uint64_t current_row, uint8_t item_index)
    1626                 :            : {
    1627                 :          0 :         struct col_desc *col_desc = g_col_desc[CORES_TAB];
    1628                 :          0 :         float res = 0.0;
    1629                 :          0 :         uint16_t col = 1;
    1630                 :            :         uint64_t irq_tmp, usr_tmp, sys_tmp, busy_tmp, idle_tmp;
    1631                 :          0 :         int color_attr = COLOR_PAIR(6);
    1632                 :          0 :         char core[MAX_CORE_STR_LEN], threads_number[MAX_THREAD_COUNT_STR_LEN], cpu_usage[MAX_FLOAT_STR_LEN],
    1633                 :          0 :              pollers_number[MAX_POLLER_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN],
    1634                 :          0 :              busy_time[MAX_TIME_STR_LEN], core_freq[MAX_CORE_FREQ_STR_LEN],
    1635                 :          0 :              in_interrupt[MAX_INTR_LEN], *status_str, sys_str[MAX_FLOAT_STR_LEN],
    1636                 :          0 :              irq_str[MAX_FLOAT_STR_LEN], cpu_str[MAX_FLOAT_STR_LEN];
    1637                 :            : 
    1638         [ #  # ]:          0 :         snprintf(threads_number, MAX_THREAD_COUNT_STR_LEN, "%ld",
    1639                 :          0 :                  g_cores_info[current_row].threads.threads_count);
    1640         [ #  # ]:          0 :         snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld", g_cores_info[current_row].pollers_count);
    1641                 :            : 
    1642   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_CORE].disabled) {
    1643         [ #  # ]:          0 :                 snprintf(core, MAX_CORE_STR_LEN, "%d", g_cores_info[current_row].lcore);
    1644                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1645                 :          0 :                               col_desc[COL_CORES_CORE].max_data_string, ALIGN_RIGHT, core);
    1646                 :          0 :                 col += col_desc[COL_CORES_CORE].max_data_string + 2;
    1647                 :            :         }
    1648                 :            : 
    1649   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_THREADS].disabled) {
    1650                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
    1651                 :          0 :                               col + (col_desc[COL_CORES_THREADS].name_len / 2), col_desc[COL_CORES_THREADS].max_data_string,
    1652                 :            :                               ALIGN_LEFT, threads_number);
    1653                 :          0 :                 col += col_desc[COL_CORES_THREADS].max_data_string + 2;
    1654                 :            :         }
    1655                 :            : 
    1656   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_POLLERS].disabled) {
    1657                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
    1658                 :          0 :                               col + (col_desc[COL_CORES_POLLERS].name_len / 2), col_desc[COL_CORES_POLLERS].max_data_string,
    1659                 :            :                               ALIGN_LEFT, pollers_number);
    1660                 :          0 :                 col += col_desc[COL_CORES_POLLERS].max_data_string;
    1661                 :            :         }
    1662                 :            : 
    1663                 :          0 :         uint64_t idle_period = g_cores_info[current_row].idle - g_cores_info[current_row].last_idle;
    1664                 :          0 :         uint64_t busy_period = g_cores_info[current_row].busy - g_cores_info[current_row].last_busy;
    1665   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_IDLE_TIME].disabled) {
    1666   [ #  #  #  # ]:          0 :                 if (g_interval_data == true) {
    1667                 :          0 :                         get_time_str(idle_period, idle_time);
    1668                 :            :                 } else {
    1669                 :          0 :                         get_time_str(g_cores_info[current_row].idle, idle_time);
    1670                 :            :                 }
    1671                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1672                 :          0 :                               col_desc[COL_CORES_IDLE_TIME].max_data_string, ALIGN_RIGHT, idle_time);
    1673                 :          0 :                 col += col_desc[COL_CORES_IDLE_TIME].max_data_string + 2;
    1674                 :            :         }
    1675                 :            : 
    1676   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_BUSY_TIME].disabled) {
    1677   [ #  #  #  # ]:          0 :                 if (g_interval_data == true) {
    1678                 :          0 :                         get_time_str(busy_period, busy_time);
    1679                 :            :                 } else {
    1680                 :          0 :                         get_time_str(g_cores_info[current_row].busy, busy_time);
    1681                 :            :                 }
    1682                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1683                 :          0 :                               col_desc[COL_CORES_BUSY_TIME].max_data_string, ALIGN_RIGHT, busy_time);
    1684                 :          0 :                 col += col_desc[COL_CORES_BUSY_TIME].max_data_string + 2;
    1685                 :            :         }
    1686                 :            : 
    1687   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_BUSY_PCT].disabled) {
    1688                 :          0 :                 get_cpu_usage_str(busy_period, busy_period + idle_period, cpu_usage);
    1689                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1690                 :          0 :                               col_desc[COL_CORES_BUSY_PCT].max_data_string, ALIGN_RIGHT, cpu_usage);
    1691                 :          0 :                 col += col_desc[COL_CORES_BUSY_PCT].max_data_string + 1;
    1692                 :            :         }
    1693                 :            : 
    1694   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_STATUS].disabled) {
    1695         [ #  # ]:          0 :                 if (busy_period > idle_period) {
    1696         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1697                 :          0 :                                 color_attr = COLOR_PAIR(6);
    1698                 :            :                         } else {
    1699                 :          0 :                                 color_attr = COLOR_PAIR(8);
    1700                 :            :                         }
    1701                 :          0 :                         status_str = "Busy";
    1702                 :            :                 } else {
    1703         [ #  # ]:          0 :                         if (item_index != g_selected_row) {
    1704                 :          0 :                                 color_attr = COLOR_PAIR(7);
    1705                 :            :                         } else {
    1706                 :          0 :                                 color_attr = COLOR_PAIR(9);
    1707                 :            :                         }
    1708                 :          0 :                         status_str = "Idle";
    1709                 :            :                 }
    1710                 :          0 :                 wattron(g_tabs[CORES_TAB], color_attr);
    1711                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1712                 :          0 :                               col_desc[COL_CORES_STATUS].max_data_string, ALIGN_RIGHT, status_str);
    1713                 :          0 :                 wattroff(g_tabs[CORES_TAB], color_attr);
    1714         [ #  # ]:          0 :                 if (item_index == g_selected_row) {
    1715                 :          0 :                         wattron(g_tabs[CORES_TAB], COLOR_PAIR(2));
    1716                 :            :                 } else {
    1717                 :          0 :                         wattron(g_tabs[CORES_TAB], COLOR_PAIR(0));
    1718                 :            :                 }
    1719                 :          0 :                 col += col_desc[COL_CORES_STATUS].max_data_string + 1;
    1720                 :            :         }
    1721                 :            : 
    1722   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_INTR].disabled) {
    1723         [ #  # ]:          0 :                 snprintf(in_interrupt, MAX_INTR_LEN, "%s",
    1724   [ #  #  #  # ]:          0 :                          g_cores_info[current_row].in_interrupt ? "Yes" : "No");
    1725                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
    1726                 :          0 :                               col + (col_desc[COL_CORES_INTR].name_len / 2),
    1727                 :          0 :                               col_desc[COL_CORES_INTR].max_data_string,
    1728                 :            :                               ALIGN_LEFT, in_interrupt);
    1729                 :          0 :                 col += col_desc[COL_CORES_INTR].max_data_string + 1;
    1730                 :            :         }
    1731                 :            : 
    1732                 :            :         /* System stats */
    1733                 :          0 :         col += 2;
    1734                 :            : 
    1735   [ #  #  #  # ]:          0 :         if (g_interval_data == true) {
    1736                 :          0 :                 irq_tmp = g_cores_info[current_row].irq - g_cores_info[current_row].last_irq;
    1737                 :          0 :                 usr_tmp = g_cores_info[current_row].usr - g_cores_info[current_row].last_usr;
    1738                 :          0 :                 sys_tmp = g_cores_info[current_row].sys - g_cores_info[current_row].last_sys;
    1739                 :          0 :                 idle_tmp = idle_period;
    1740                 :          0 :                 busy_tmp = busy_period;
    1741                 :            :         } else {
    1742                 :          0 :                 irq_tmp = g_cores_info[current_row].irq;
    1743                 :          0 :                 usr_tmp = g_cores_info[current_row].usr;
    1744                 :          0 :                 sys_tmp = g_cores_info[current_row].sys;
    1745                 :          0 :                 idle_tmp = g_cores_info[current_row].idle;
    1746                 :          0 :                 busy_tmp = g_cores_info[current_row].busy;
    1747                 :            :         }
    1748                 :            : 
    1749   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_SYS_PCT].disabled) {
    1750         [ #  # ]:          0 :                 if (usr_tmp + sys_tmp > 0) {
    1751                 :          0 :                         res = (((float)sys_tmp /
    1752                 :          0 :                                 (usr_tmp + sys_tmp)) * 100);
    1753                 :            :                 }
    1754         [ #  # ]:          0 :                 snprintf(sys_str, sizeof(sys_str), "%.2f", res);
    1755                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1756                 :          0 :                               col_desc[COL_CORES_SYS_PCT].max_data_string, ALIGN_RIGHT, sys_str);
    1757                 :          0 :                 col += col_desc[COL_CORES_SYS_PCT].max_data_string + 1;
    1758                 :            :         }
    1759                 :            : 
    1760   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_IRQ_PCT].disabled) {
    1761                 :          0 :                 res = 0.0;
    1762         [ #  # ]:          0 :                 if (usr_tmp + sys_tmp + irq_tmp > 0) {
    1763                 :          0 :                         res = (((float)irq_tmp / (usr_tmp + sys_tmp + irq_tmp)) * 100);
    1764                 :            :                 }
    1765         [ #  # ]:          0 :                 snprintf(irq_str, sizeof(irq_str), "%.2f", res);
    1766                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1767                 :          0 :                               col_desc[COL_CORES_IRQ_PCT].max_data_string, ALIGN_RIGHT, irq_str);
    1768                 :          0 :                 col += col_desc[COL_CORES_IRQ_PCT].max_data_string + 1;
    1769                 :            :         }
    1770                 :            : 
    1771   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_CPU_PCT].disabled) {
    1772                 :          0 :                 res = 0.0;
    1773         [ #  # ]:          0 :                 if (busy_tmp + idle_tmp + sys_tmp + irq_tmp > 0) {
    1774                 :          0 :                         res = (((float)(busy_tmp + irq_tmp + sys_tmp) /
    1775                 :          0 :                                 (busy_tmp + idle_tmp + sys_tmp + irq_tmp)) * 100);
    1776                 :            :                 }
    1777         [ #  # ]:          0 :                 snprintf(cpu_str, sizeof(cpu_str), "%.2f", res);
    1778                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1779                 :          0 :                               col_desc[COL_CORES_CPU_PCT].max_data_string, ALIGN_RIGHT, cpu_str);
    1780                 :          0 :                 col += col_desc[COL_CORES_CPU_PCT].max_data_string + 1;
    1781                 :            :         }
    1782                 :            : 
    1783   [ #  #  #  # ]:          0 :         if (!col_desc[COL_CORES_CORE_FREQ].disabled) {
    1784         [ #  # ]:          0 :                 if (!g_cores_info[current_row].core_freq) {
    1785         [ #  # ]:          0 :                         snprintf(core_freq, MAX_CORE_FREQ_STR_LEN, "%s", "N/A");
    1786                 :            :                 } else {
    1787         [ #  # ]:          0 :                         snprintf(core_freq, MAX_CORE_FREQ_STR_LEN, "%" PRIu32,
    1788                 :          0 :                                  g_cores_info[current_row].core_freq);
    1789                 :            :                 }
    1790                 :          0 :                 print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
    1791                 :          0 :                               col_desc[COL_CORES_CORE_FREQ].max_data_string, ALIGN_RIGHT, core_freq);
    1792                 :            :         }
    1793                 :          0 : }
    1794                 :            : 
    1795                 :            : static uint8_t
    1796                 :          0 : refresh_cores_tab(uint8_t current_page)
    1797                 :            : {
    1798                 :            :         uint64_t i;
    1799                 :          0 :         uint16_t count = 0;
    1800                 :            :         uint8_t max_pages, item_index;
    1801                 :            : 
    1802                 :          0 :         count = g_last_cores_count;
    1803                 :            : 
    1804         [ #  # ]:          0 :         max_pages = (count + g_max_row - WINDOW_HEADER - 1) / (g_max_row - WINDOW_HEADER);
    1805                 :            : 
    1806                 :          0 :         for (i = current_page * g_max_data_rows;
    1807         [ #  # ]:          0 :              i < spdk_min(count, (uint64_t)((current_page + 1) * g_max_data_rows));
    1808                 :          0 :              i++) {
    1809                 :          0 :                 item_index = i - (current_page * g_max_data_rows);
    1810                 :            : 
    1811                 :          0 :                 draw_row_background(item_index, CORES_TAB);
    1812                 :          0 :                 draw_core_tab_row(i, item_index);
    1813                 :            : 
    1814         [ #  # ]:          0 :                 if (item_index == g_selected_row) {
    1815                 :          0 :                         wattroff(g_tabs[CORES_TAB], COLOR_PAIR(2));
    1816                 :            :                 }
    1817                 :            :         }
    1818                 :            : 
    1819                 :          0 :         g_max_selected_row = i - current_page * g_max_data_rows - 1;
    1820                 :            : 
    1821                 :          0 :         return max_pages;
    1822                 :            : }
    1823                 :            : 
    1824                 :            : static uint8_t
    1825                 :          0 : refresh_tab(enum tabs tab, uint8_t current_page)
    1826                 :            : {
    1827                 :          0 :         uint8_t (*refresh_function[NUMBER_OF_TABS])(uint8_t current_page) = {refresh_threads_tab, refresh_pollers_tab, refresh_cores_tab};
    1828                 :          0 :         int color_pair[NUMBER_OF_TABS] = {COLOR_PAIR(2), COLOR_PAIR(2), COLOR_PAIR(2)};
    1829                 :            :         int i;
    1830                 :          0 :         uint8_t max_pages = 0;
    1831                 :            : 
    1832                 :          0 :         color_pair[tab] = COLOR_PAIR(1);
    1833                 :            : 
    1834         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    1835                 :          0 :                 wbkgd(g_tab_win[i], color_pair[i]);
    1836                 :            :         }
    1837                 :            : 
    1838                 :          0 :         max_pages = (*refresh_function[tab])(current_page);
    1839                 :            : 
    1840         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    1841                 :          0 :                 wnoutrefresh(g_tab_win[i]);
    1842                 :            :         }
    1843                 :          0 :         draw_menu_win();
    1844                 :            : 
    1845                 :          0 :         return max_pages;
    1846                 :            : }
    1847                 :            : 
    1848                 :            : static void
    1849                 :          0 : print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
    1850                 :            : {
    1851                 :            :         int length, temp;
    1852                 :            : 
    1853         [ #  # ]:          0 :         length = strlen(string);
    1854                 :          0 :         temp = (width - length) / 2;
    1855                 :          0 :         wattron(win, color);
    1856                 :          0 :         mvwprintw(win, starty, startx + temp, "%s", string);
    1857                 :          0 :         wattroff(win, color);
    1858                 :          0 : }
    1859                 :            : 
    1860                 :            : static void
    1861                 :          0 : print_left(WINDOW *win, int starty, int startx, int width, const char *string, chtype color)
    1862                 :            : {
    1863                 :          0 :         wattron(win, color);
    1864                 :          0 :         mvwprintw(win, starty, startx, "%s", string);
    1865                 :          0 :         wattroff(win, color);
    1866                 :          0 : }
    1867                 :            : 
    1868                 :            : static void
    1869                 :          0 : apply_filters(enum tabs tab)
    1870                 :            : {
    1871                 :          0 :         wclear(g_tabs[tab]);
    1872                 :          0 :         draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
    1873                 :          0 : }
    1874                 :            : 
    1875                 :            : static ITEM **
    1876                 :          0 : draw_filtering_menu(uint8_t position, WINDOW *filter_win, uint8_t tab, MENU **my_menu)
    1877                 :            : {
    1878                 :          0 :         const int ADDITIONAL_ELEMENTS = 3;
    1879                 :          0 :         const int ROW_PADDING = 6;
    1880                 :          0 :         const int WINDOW_START_X = 1;
    1881                 :          0 :         const int WINDOW_START_Y = 3;
    1882                 :          0 :         const int WINDOW_COLUMNS = 2;
    1883                 :          0 :         struct col_desc *col_desc = g_col_desc[tab];
    1884                 :            :         ITEM **my_items;
    1885                 :            :         MENU *menu;
    1886                 :            :         int i, elements;
    1887                 :          0 :         uint8_t len = 0;
    1888                 :            : 
    1889         [ #  # ]:          0 :         for (i = 0; col_desc[i].name != NULL; ++i) {
    1890                 :          0 :                 len = spdk_max(col_desc[i].name_len, len);
    1891                 :            :         }
    1892                 :            : 
    1893                 :          0 :         elements = i;
    1894                 :            : 
    1895                 :          0 :         my_items = (ITEM **)calloc(elements * WINDOW_COLUMNS + ADDITIONAL_ELEMENTS, sizeof(ITEM *));
    1896         [ #  # ]:          0 :         if (my_items == NULL) {
    1897   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate an item list in draw_filtering_menu.\n");
    1898                 :          0 :                 return NULL;
    1899                 :            :         }
    1900                 :            : 
    1901         [ #  # ]:          0 :         for (i = 0; i < elements * 2; i++) {
    1902         [ #  # ]:          0 :                 my_items[i] = new_item(col_desc[i / WINDOW_COLUMNS].name, NULL);
    1903                 :          0 :                 i++;
    1904   [ #  #  #  #  :          0 :                 my_items[i] = new_item(col_desc[i / WINDOW_COLUMNS].disabled ? "[ ]" : "[*]", NULL);
                   #  # ]
    1905                 :            :         }
    1906                 :            : 
    1907                 :          0 :         my_items[i] = new_item("     CLOSE", NULL);
    1908                 :          0 :         set_item_userptr(my_items[i], apply_filters);
    1909                 :            : 
    1910                 :          0 :         menu = new_menu((ITEM **)my_items);
    1911                 :            : 
    1912                 :          0 :         menu_opts_off(menu, O_SHOWDESC);
    1913                 :          0 :         set_menu_format(menu, elements + 1, WINDOW_COLUMNS);
    1914                 :            : 
    1915                 :          0 :         set_menu_win(menu, filter_win);
    1916                 :          0 :         set_menu_sub(menu, derwin(filter_win, elements + 1, len + ROW_PADDING, WINDOW_START_Y,
    1917                 :            :                                   WINDOW_START_X));
    1918                 :            : 
    1919                 :          0 :         *my_menu = menu;
    1920                 :            : 
    1921                 :          0 :         post_menu(menu);
    1922                 :          0 :         refresh();
    1923                 :          0 :         wrefresh(filter_win);
    1924                 :            : 
    1925   [ #  #  #  # ]:          0 :         for (i = 0; i < position / WINDOW_COLUMNS; i++) {
    1926                 :          0 :                 menu_driver(menu, REQ_DOWN_ITEM);
    1927                 :            :         }
    1928                 :            : 
    1929                 :          0 :         return my_items;
    1930                 :            : }
    1931                 :            : 
    1932                 :            : static void
    1933                 :          0 : delete_filtering_menu(MENU *my_menu, ITEM **my_items, uint8_t elements)
    1934                 :            : {
    1935                 :            :         int i;
    1936                 :            : 
    1937                 :          0 :         unpost_menu(my_menu);
    1938                 :          0 :         free_menu(my_menu);
    1939         [ #  # ]:          0 :         for (i = 0; i < elements * 2 + 2; ++i) {
    1940                 :          0 :                 free_item(my_items[i]);
    1941                 :            :         }
    1942                 :          0 :         free(my_items);
    1943                 :          0 : }
    1944                 :            : 
    1945                 :            : static ITEM **
    1946                 :          0 : refresh_filtering_menu(MENU **my_menu, WINDOW *filter_win, uint8_t tab, ITEM **my_items,
    1947                 :            :                        uint8_t elements, uint8_t position)
    1948                 :            : {
    1949                 :          0 :         delete_filtering_menu(*my_menu, my_items, elements);
    1950                 :          0 :         return draw_filtering_menu(position, filter_win, tab, my_menu);
    1951                 :            : }
    1952                 :            : 
    1953                 :            : static void
    1954                 :          0 : filter_columns(uint8_t tab)
    1955                 :            : {
    1956                 :          0 :         const int WINDOW_HEADER_LEN = 5;
    1957                 :          0 :         const int WINDOW_BORDER_LEN = 8;
    1958                 :          0 :         const int WINDOW_HEADER_END_LINE = 2;
    1959                 :          0 :         const int WINDOW_COLUMNS = 2;
    1960                 :          0 :         struct col_desc *col_desc = g_col_desc[tab];
    1961                 :            :         PANEL *filter_panel;
    1962                 :            :         WINDOW *filter_win;
    1963                 :            :         ITEM **my_items;
    1964                 :          0 :         MENU *my_menu = NULL;
    1965                 :            :         int i, c, elements;
    1966                 :          0 :         bool stop_loop = false;
    1967                 :            :         ITEM *cur;
    1968                 :            :         void (*p)(enum tabs tab);
    1969                 :          0 :         uint8_t current_index, len = 0;
    1970                 :          0 :         bool disabled[TABS_COL_COUNT];
    1971                 :            : 
    1972         [ #  # ]:          0 :         for (i = 0; col_desc[i].name != NULL; ++i) {
    1973                 :          0 :                 len = spdk_max(col_desc[i].name_len, len);
    1974                 :            :         }
    1975                 :            : 
    1976                 :          0 :         elements = i;
    1977                 :            : 
    1978                 :          0 :         filter_win = newwin(elements + WINDOW_HEADER_LEN, len + WINDOW_BORDER_LEN,
    1979                 :          0 :                             (g_max_row - elements - 1) / 2, (g_max_col - len) / 2);
    1980         [ #  # ]:          0 :         assert(filter_win != NULL);
    1981                 :          0 :         keypad(filter_win, TRUE);
    1982                 :          0 :         filter_panel = new_panel(filter_win);
    1983         [ #  # ]:          0 :         assert(filter_panel != NULL);
    1984                 :            : 
    1985                 :          0 :         top_panel(filter_panel);
    1986                 :          0 :         update_panels();
    1987                 :          0 :         doupdate();
    1988                 :            : 
    1989                 :          0 :         box(filter_win, 0, 0);
    1990                 :            : 
    1991                 :          0 :         print_in_middle(filter_win, 1, 0, len + WINDOW_BORDER_LEN, "Filtering", COLOR_PAIR(3));
    1992         [ #  # ]:          0 :         mvwaddch(filter_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
    1993         [ #  # ]:          0 :         mvwhline(filter_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, len + WINDOW_BORDER_LEN - 2);
    1994         [ #  # ]:          0 :         mvwaddch(filter_win, WINDOW_HEADER_END_LINE, len + WINDOW_BORDER_LEN - 1, ACS_RTEE);
    1995                 :            : 
    1996                 :          0 :         my_items = draw_filtering_menu(0, filter_win, tab, &my_menu);
    1997   [ #  #  #  # ]:          0 :         if (my_items == NULL || my_menu == NULL) {
    1998                 :          0 :                 goto fail;
    1999                 :            :         }
    2000                 :            : 
    2001         [ #  # ]:          0 :         for (int i = 0; i < TABS_COL_COUNT; i++) {
    2002         [ #  # ]:          0 :                 disabled[i] = col_desc[i].disabled;
    2003                 :            :         }
    2004                 :            : 
    2005         [ #  # ]:          0 :         while (!stop_loop) {
    2006                 :          0 :                 c = wgetch(filter_win);
    2007                 :            : 
    2008   [ #  #  #  #  :          0 :                 switch (c) {
                   #  # ]
    2009                 :          0 :                 case KEY_DOWN:
    2010                 :          0 :                         menu_driver(my_menu, REQ_DOWN_ITEM);
    2011                 :          0 :                         break;
    2012                 :          0 :                 case KEY_UP:
    2013                 :          0 :                         menu_driver(my_menu, REQ_UP_ITEM);
    2014                 :          0 :                         break;
    2015                 :          0 :                 case 27: /* ESC */
    2016                 :            :                 case 'q':
    2017         [ #  # ]:          0 :                         for (int i = 0; i < TABS_COL_COUNT; i++) {
    2018                 :          0 :                                 cur = current_item(my_menu);
    2019         [ #  # ]:          0 :                                 col_desc[i].disabled = disabled[i];
    2020                 :            : 
    2021                 :          0 :                                 my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
    2022                 :          0 :                                                                   item_index(cur) + 1);
    2023   [ #  #  #  # ]:          0 :                                 if (my_items == NULL || my_menu == NULL) {
    2024                 :          0 :                                         goto fail;
    2025                 :            :                                 }
    2026                 :            :                         }
    2027                 :            : 
    2028                 :          0 :                         stop_loop = true;
    2029                 :          0 :                         break;
    2030                 :          0 :                 case ' ': /* Space */
    2031                 :          0 :                         cur = current_item(my_menu);
    2032         [ #  # ]:          0 :                         current_index = item_index(cur) / WINDOW_COLUMNS;
    2033         [ #  # ]:          0 :                         col_desc[current_index].disabled = !col_desc[current_index].disabled;
    2034                 :          0 :                         my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
    2035                 :          0 :                                                           item_index(cur) + 1);
    2036   [ #  #  #  # ]:          0 :                         if (my_items == NULL || my_menu == NULL) {
    2037                 :          0 :                                 goto fail;
    2038                 :            :                         }
    2039                 :          0 :                         break;
    2040                 :          0 :                 case 10: /* Enter */
    2041                 :          0 :                         cur = current_item(my_menu);
    2042         [ #  # ]:          0 :                         current_index = item_index(cur) / WINDOW_COLUMNS;
    2043         [ #  # ]:          0 :                         if (current_index == elements) {
    2044                 :          0 :                                 stop_loop = true;
    2045                 :          0 :                                 p = item_userptr(cur);
    2046                 :          0 :                                 p(tab);
    2047                 :            :                         } else {
    2048         [ #  # ]:          0 :                                 col_desc[current_index].disabled = !col_desc[current_index].disabled;
    2049                 :          0 :                                 my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
    2050                 :          0 :                                                                   item_index(cur) + 1);
    2051   [ #  #  #  # ]:          0 :                                 if (my_items == NULL || my_menu == NULL) {
    2052                 :          0 :                                         goto fail;
    2053                 :            :                                 }
    2054                 :            :                         }
    2055                 :          0 :                         break;
    2056                 :            :                 }
    2057                 :          0 :                 wrefresh(filter_win);
    2058                 :            :         }
    2059                 :            : 
    2060                 :          0 :         delete_filtering_menu(my_menu, my_items, elements);
    2061                 :            : 
    2062                 :          0 :         del_panel(filter_panel);
    2063                 :          0 :         delwin(filter_win);
    2064                 :            : 
    2065                 :          0 :         wclear(g_menu_win);
    2066                 :          0 :         draw_menu_win();
    2067                 :          0 :         return;
    2068                 :            : 
    2069                 :          0 : fail:
    2070   [ #  #  #  # ]:          0 :         fprintf(stderr, "Unable to filter the columns due to allocation failure.\n");
    2071                 :          0 :         assert(false);
    2072                 :            : }
    2073                 :            : 
    2074                 :            : static void
    2075                 :          0 : sort_type(enum tabs tab, int item_index)
    2076                 :            : {
    2077                 :          0 :         g_current_sort_col[tab] = item_index;
    2078                 :          0 : }
    2079                 :            : 
    2080                 :            : static void
    2081                 :          0 : sort_type2(enum tabs tab, int item_index)
    2082                 :            : {
    2083                 :          0 :         g_current_sort_col2[tab] = item_index;
    2084                 :          0 : }
    2085                 :            : 
    2086                 :            : static void
    2087                 :          0 : change_sorting(uint8_t tab, int winnum, bool *pstop_loop)
    2088                 :            : {
    2089                 :          0 :         const int WINDOW_HEADER_LEN = 4;
    2090                 :          0 :         const int WINDOW_BORDER_LEN = 3;
    2091                 :          0 :         const int WINDOW_START_X = 1;
    2092                 :          0 :         const int WINDOW_START_Y = 4;
    2093                 :          0 :         const int WINDOW_HEADER_END_LINE = 3;
    2094                 :          0 :         const int WINDOW_MIN_WIDTH = 31;
    2095                 :            :         PANEL *sort_panel;
    2096                 :            :         WINDOW *sort_win;
    2097                 :            :         ITEM **my_items;
    2098                 :            :         MENU *my_menu;
    2099                 :            :         int i, c, elements;
    2100                 :          0 :         bool stop_loop = false;
    2101                 :            :         ITEM *cur;
    2102                 :            :         char *name;
    2103                 :            :         char *help;
    2104                 :            :         void (*p)(enum tabs tab, int item_index);
    2105                 :          0 :         uint8_t len = WINDOW_MIN_WIDTH;
    2106                 :            : 
    2107         [ #  # ]:          0 :         for (i = 0; g_col_desc[tab][i].name != NULL; ++i) {
    2108                 :          0 :                 len = spdk_max(len, g_col_desc[tab][i].name_len);
    2109                 :            :         }
    2110                 :            : 
    2111                 :          0 :         elements = i;
    2112                 :            : 
    2113                 :          0 :         my_items = (ITEM **)calloc(elements + 1, sizeof(ITEM *));
    2114         [ #  # ]:          0 :         if (my_items == NULL) {
    2115   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate an item list in change_sorting.\n");
    2116                 :          0 :                 return;
    2117                 :            :         }
    2118                 :            : 
    2119         [ #  # ]:          0 :         for (i = 0; i < elements; ++i) {
    2120                 :          0 :                 my_items[i] = new_item(g_col_desc[tab][i].name, NULL);
    2121         [ #  # ]:          0 :                 set_item_userptr(my_items[i], (winnum == 0) ? sort_type : sort_type2);
    2122                 :            :         }
    2123                 :            : 
    2124                 :          0 :         my_menu = new_menu((ITEM **)my_items);
    2125                 :            : 
    2126                 :          0 :         menu_opts_off(my_menu, O_SHOWDESC);
    2127                 :            : 
    2128                 :          0 :         sort_win = newwin(elements + WINDOW_HEADER_LEN + 1, len + WINDOW_BORDER_LEN,
    2129                 :          0 :                           (g_max_row - elements) / 2,
    2130                 :          0 :                           (g_max_col - len) / 2 - len + len * winnum);
    2131         [ #  # ]:          0 :         assert(sort_win != NULL);
    2132                 :          0 :         keypad(sort_win, TRUE);
    2133                 :          0 :         sort_panel = new_panel(sort_win);
    2134         [ #  # ]:          0 :         assert(sort_panel != NULL);
    2135                 :            : 
    2136                 :          0 :         top_panel(sort_panel);
    2137                 :          0 :         update_panels();
    2138                 :          0 :         doupdate();
    2139                 :            : 
    2140                 :          0 :         set_menu_win(my_menu, sort_win);
    2141                 :          0 :         set_menu_sub(my_menu, derwin(sort_win, elements, len + 1, WINDOW_START_Y, WINDOW_START_X));
    2142                 :          0 :         box(sort_win, 0, 0);
    2143                 :            : 
    2144         [ #  # ]:          0 :         if (winnum == 0) {
    2145                 :          0 :                 name = "Sorting #1";
    2146                 :          0 :                 help = "Right key for second sorting";
    2147                 :            :         } else {
    2148                 :          0 :                 name = "Sorting #2";
    2149                 :          0 :                 help = "Left key for first sorting";
    2150                 :            :         }
    2151                 :            : 
    2152                 :          0 :         print_in_middle(sort_win, 1, 0, len + WINDOW_BORDER_LEN, name, COLOR_PAIR(3));
    2153                 :          0 :         print_in_middle(sort_win, 2, 0, len + WINDOW_BORDER_LEN, help, COLOR_PAIR(3));
    2154         [ #  # ]:          0 :         mvwaddch(sort_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
    2155         [ #  # ]:          0 :         mvwhline(sort_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, len + 1);
    2156         [ #  # ]:          0 :         mvwaddch(sort_win, WINDOW_HEADER_END_LINE, len + WINDOW_BORDER_LEN - 1, ACS_RTEE);
    2157                 :            : 
    2158                 :          0 :         post_menu(my_menu);
    2159                 :          0 :         refresh();
    2160                 :          0 :         wrefresh(sort_win);
    2161                 :            : 
    2162   [ #  #  #  # ]:          0 :         while (!stop_loop) {
    2163                 :          0 :                 c = wgetch(sort_win);
    2164                 :            :                 /*
    2165                 :            :                  * First sorting window:
    2166                 :            :                  * Up/Down - select first sorting column;
    2167                 :            :                  * Enter - apply current column;
    2168                 :            :                  * Right - open second sorting window.
    2169                 :            :                  * Second sorting window:
    2170                 :            :                  * Up/Down - select second sorting column;
    2171                 :            :                  * Enter - apply current column of both sorting windows;
    2172                 :            :                  * Left - exit second window and reset second sorting key;
    2173                 :            :                  * Right - do nothing.
    2174                 :            :                  */
    2175   [ #  #  #  #  :          0 :                 switch (c) {
                #  #  # ]
    2176                 :          0 :                 case KEY_DOWN:
    2177                 :          0 :                         menu_driver(my_menu, REQ_DOWN_ITEM);
    2178                 :          0 :                         break;
    2179                 :          0 :                 case KEY_UP:
    2180                 :          0 :                         menu_driver(my_menu, REQ_UP_ITEM);
    2181                 :          0 :                         break;
    2182                 :          0 :                 case KEY_RIGHT:
    2183         [ #  # ]:          0 :                         if (winnum > 0) {
    2184                 :          0 :                                 break;
    2185                 :            :                         }
    2186                 :          0 :                         change_sorting(tab, winnum + 1, &stop_loop);
    2187                 :            :                         /* Restore input. */
    2188                 :          0 :                         keypad(sort_win, TRUE);
    2189                 :          0 :                         post_menu(my_menu);
    2190                 :          0 :                         refresh();
    2191                 :          0 :                         wrefresh(sort_win);
    2192         [ #  # ]:          0 :                         redrawwin(sort_win);
    2193         [ #  # ]:          0 :                         if (winnum == 0) {
    2194                 :          0 :                                 cur = current_item(my_menu);
    2195                 :          0 :                                 p = item_userptr(cur);
    2196                 :          0 :                                 p(tab, item_index(cur));
    2197                 :            :                         }
    2198                 :          0 :                         break;
    2199                 :          0 :                 case 27: /* ESC */
    2200                 :          0 :                         stop_loop = true;
    2201                 :          0 :                         break;
    2202                 :          0 :                 case KEY_LEFT:
    2203         [ #  # ]:          0 :                         if (winnum > 0) {
    2204                 :          0 :                                 sort_type2(tab, COL_THREADS_NONE);
    2205                 :            :                         }
    2206                 :            :                 /* FALLTHROUGH */
    2207                 :            :                 case 10: /* Enter */
    2208                 :          0 :                         stop_loop = true;
    2209   [ #  #  #  # ]:          0 :                         if (winnum > 0 && c == 10) {
    2210                 :          0 :                                 *pstop_loop = true;
    2211                 :            :                         }
    2212         [ #  # ]:          0 :                         if (c == 10) {
    2213                 :          0 :                                 cur = current_item(my_menu);
    2214                 :          0 :                                 p = item_userptr(cur);
    2215                 :          0 :                                 p(tab, item_index(cur));
    2216                 :            :                         }
    2217                 :          0 :                         break;
    2218                 :            :                 }
    2219                 :          0 :                 wrefresh(sort_win);
    2220                 :            :         }
    2221                 :            : 
    2222         [ #  # ]:          0 :         if (winnum == 0) {
    2223                 :          0 :                 wclear(g_tabs[tab]);
    2224                 :          0 :                 draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
    2225                 :            :         }
    2226                 :            : 
    2227                 :          0 :         unpost_menu(my_menu);
    2228                 :          0 :         free_menu(my_menu);
    2229                 :            : 
    2230         [ #  # ]:          0 :         for (i = 0; i < elements; ++i) {
    2231                 :          0 :                 free_item(my_items[i]);
    2232                 :            :         }
    2233                 :            : 
    2234                 :          0 :         free(my_items);
    2235                 :            : 
    2236                 :          0 :         del_panel(sort_panel);
    2237                 :          0 :         delwin(sort_win);
    2238                 :            : 
    2239         [ #  # ]:          0 :         if (winnum == 0) {
    2240                 :          0 :                 wclear(g_menu_win);
    2241                 :          0 :                 draw_menu_win();
    2242                 :            :         }
    2243                 :            : }
    2244                 :            : 
    2245                 :            : static int
    2246                 :          0 : check_resize_interface(uint8_t active_tab, uint8_t *current_page)
    2247                 :            : {
    2248                 :            :         int max_row, max_col;
    2249                 :          0 :         uint16_t required_size = WINDOW_HEADER + 1;
    2250                 :            : 
    2251                 :            :         /* Check if interface has to be resized (terminal size changed) */
    2252   [ #  #  #  # ]:          0 :         getmaxyx(stdscr, max_row, max_col);
    2253                 :            : 
    2254   [ #  #  #  # ]:          0 :         if (max_row != g_max_row || max_col != g_max_col) {
    2255         [ #  # ]:          0 :                 if (max_row != g_max_row) {
    2256                 :          0 :                         *current_page = 0;
    2257                 :            :                 }
    2258                 :          0 :                 g_max_row = spdk_max(max_row, required_size);
    2259                 :          0 :                 g_max_col = max_col;
    2260                 :          0 :                 g_data_win_size = g_max_row - required_size + 1;
    2261                 :          0 :                 g_max_data_rows = g_max_row - WINDOW_HEADER;
    2262                 :          0 :                 resize_interface(active_tab);
    2263                 :            : 
    2264                 :          0 :                 return 1;
    2265                 :            :         }
    2266                 :            : 
    2267                 :          0 :         return 0;
    2268                 :            : }
    2269                 :            : 
    2270                 :            : static void
    2271                 :          0 : change_refresh_rate(void)
    2272                 :            : {
    2273                 :          0 :         const int WINDOW_HEADER_END_LINE = 2;
    2274                 :            :         PANEL *refresh_panel;
    2275                 :            :         WINDOW *refresh_win;
    2276                 :            :         int c;
    2277                 :          0 :         bool stop_loop = false;
    2278                 :          0 :         uint32_t rr_tmp, refresh_rate = 0;
    2279                 :          0 :         char refresh_rate_str[MAX_STRING_LEN];
    2280                 :            : 
    2281                 :          0 :         refresh_win = newwin(RR_WIN_HEIGHT, RR_WIN_WIDTH, (g_max_row - RR_WIN_HEIGHT - 1) / 2,
    2282                 :          0 :                              (g_max_col - RR_WIN_WIDTH) / 2);
    2283         [ #  # ]:          0 :         assert(refresh_win != NULL);
    2284                 :          0 :         keypad(refresh_win, TRUE);
    2285                 :          0 :         refresh_panel = new_panel(refresh_win);
    2286         [ #  # ]:          0 :         assert(refresh_panel != NULL);
    2287                 :            : 
    2288                 :          0 :         top_panel(refresh_panel);
    2289                 :          0 :         update_panels();
    2290                 :          0 :         doupdate();
    2291                 :            : 
    2292                 :          0 :         box(refresh_win, 0, 0);
    2293                 :            : 
    2294                 :          0 :         print_in_middle(refresh_win, 1, 0, RR_WIN_WIDTH + 1, "Enter refresh rate value [s]", COLOR_PAIR(3));
    2295         [ #  # ]:          0 :         mvwaddch(refresh_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
    2296         [ #  # ]:          0 :         mvwhline(refresh_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, RR_WIN_WIDTH - 2);
    2297         [ #  # ]:          0 :         mvwaddch(refresh_win, WINDOW_HEADER_END_LINE, RR_WIN_WIDTH, ACS_RTEE);
    2298                 :          0 :         mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1, (RR_WIN_WIDTH - 1) / 2, "%d", refresh_rate);
    2299                 :            : 
    2300                 :          0 :         refresh();
    2301                 :          0 :         wrefresh(refresh_win);
    2302                 :            : 
    2303         [ #  # ]:          0 :         while (!stop_loop) {
    2304                 :          0 :                 c = wgetch(refresh_win);
    2305                 :            : 
    2306   [ #  #  #  #  :          0 :                 switch (c) {
                      # ]
    2307                 :          0 :                 case '0':
    2308                 :            :                 case '1':
    2309                 :            :                 case '2':
    2310                 :            :                 case '3':
    2311                 :            :                 case '4':
    2312                 :            :                 case '5':
    2313                 :            :                 case '6':
    2314                 :            :                 case '7':
    2315                 :            :                 case '8':
    2316                 :            :                 case '9':
    2317                 :          0 :                         rr_tmp = refresh_rate * 10 + c - '0';
    2318                 :            : 
    2319         [ #  # ]:          0 :                         if (rr_tmp <= RR_MAX_VALUE) {
    2320                 :          0 :                                 refresh_rate = rr_tmp;
    2321                 :          0 :                                 snprintf(refresh_rate_str, MAX_STRING_LEN - 1, "%d", refresh_rate);
    2322                 :          0 :                                 mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
    2323                 :          0 :                                           (RR_WIN_WIDTH - 1 - strlen(refresh_rate_str)) / 2, "%d", refresh_rate);
    2324                 :          0 :                                 refresh();
    2325                 :          0 :                                 wrefresh(refresh_win);
    2326                 :            :                         }
    2327                 :          0 :                         break;
    2328                 :          0 :                 case KEY_BACKSPACE:
    2329                 :            :                 case 127:
    2330                 :            :                 case '\b':
    2331                 :          0 :                         refresh_rate = refresh_rate / 10;
    2332                 :          0 :                         snprintf(refresh_rate_str, MAX_STRING_LEN - 1, "%d", refresh_rate);
    2333                 :          0 :                         mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
    2334                 :          0 :                                   (RR_WIN_WIDTH - 1 - strlen(refresh_rate_str) - 2) / 2, "       ");
    2335                 :          0 :                         mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
    2336                 :          0 :                                   (RR_WIN_WIDTH - 1 - strlen(refresh_rate_str)) / 2, "%d", refresh_rate);
    2337                 :          0 :                         refresh();
    2338                 :          0 :                         wrefresh(refresh_win);
    2339                 :          0 :                         break;
    2340                 :          0 :                 case 27: /* ESC */
    2341                 :            :                 case 'q':
    2342                 :          0 :                         stop_loop = true;
    2343                 :          0 :                         break;
    2344                 :          0 :                 case 10: /* Enter */
    2345                 :          0 :                         pthread_mutex_lock(&g_thread_lock);
    2346                 :          0 :                         g_sleep_time = refresh_rate;
    2347                 :          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2348                 :          0 :                         stop_loop = true;
    2349                 :          0 :                         break;
    2350                 :            :                 }
    2351                 :          0 :                 wrefresh(refresh_win);
    2352                 :            :         }
    2353                 :            : 
    2354                 :          0 :         del_panel(refresh_panel);
    2355                 :          0 :         delwin(refresh_win);
    2356                 :          0 : }
    2357                 :            : 
    2358                 :            : static void
    2359                 :          0 : free_poller_history(void)
    2360                 :            : {
    2361                 :            :         struct run_counter_history *history, *tmp;
    2362                 :            : 
    2363         [ #  # ]:          0 :         TAILQ_FOREACH_SAFE(history, &g_run_counter_history, link, tmp) {
    2364         [ #  # ]:          0 :                 TAILQ_REMOVE(&g_run_counter_history, history, link);
    2365                 :          0 :                 free(history);
    2366                 :            :         }
    2367                 :          0 : }
    2368                 :            : 
    2369                 :            : static uint64_t
    2370                 :          0 : get_position_for_window(uint64_t window_size, uint64_t max_size)
    2371                 :            : {
    2372                 :            :         /* This function calculates position for pop-up detail window.
    2373                 :            :          * Since horizontal and vertical positions are calculated the same way
    2374                 :            :          * there is no need for separate functions. */
    2375                 :          0 :         window_size = spdk_min(window_size, max_size);
    2376                 :            : 
    2377                 :          0 :         return (max_size - window_size) / 2;
    2378                 :            : }
    2379                 :            : 
    2380                 :            : static void
    2381                 :          0 : print_bottom_message(char *msg)
    2382                 :            : {
    2383                 :            :         uint64_t i;
    2384                 :            : 
    2385         [ #  # ]:          0 :         for (i = 1; i < (uint64_t)g_max_col - 1; i++) {
    2386                 :          0 :                 mvprintw(g_max_row - 1, i, " ");
    2387                 :            :         }
    2388         [ #  # ]:          0 :         mvprintw(g_max_row - 1, g_max_col - strlen(msg) - 2, "%s", msg);
    2389                 :          0 : }
    2390                 :            : 
    2391                 :            : static void
    2392                 :          0 : draw_thread_win_content(WINDOW *thread_win, struct rpc_thread_info *thread_info)
    2393                 :            : {
    2394                 :            :         uint64_t current_row, i, time;
    2395                 :          0 :         char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];
    2396                 :            : 
    2397                 :          0 :         box(thread_win, 0, 0);
    2398                 :            : 
    2399                 :          0 :         print_in_middle(thread_win, 1, 0, THREAD_WIN_WIDTH, thread_info->name,
    2400                 :            :                         COLOR_PAIR(3));
    2401         [ #  # ]:          0 :         mvwhline(thread_win, 2, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
    2402         [ #  # ]:          0 :         mvwaddch(thread_win, 2, THREAD_WIN_WIDTH, ACS_RTEE);
    2403                 :            : 
    2404                 :          0 :         print_left(thread_win, 3, THREAD_WIN_FIRST_COL, THREAD_WIN_WIDTH,
    2405                 :            :                    "Core:                Idle [us]:            Busy [us]:", COLOR_PAIR(5));
    2406                 :          0 :         mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 6, "%d",
    2407                 :            :                   thread_info->core_num);
    2408                 :            : 
    2409   [ #  #  #  # ]:          0 :         if (g_interval_data) {
    2410                 :          0 :                 get_time_str(thread_info->idle - thread_info->last_idle, idle_time);
    2411                 :          0 :                 mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 32, "%s", idle_time);
    2412                 :          0 :                 get_time_str(thread_info->busy - thread_info->last_busy, busy_time);
    2413                 :          0 :                 mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 54, "%s", busy_time);
    2414                 :            :         } else {
    2415                 :          0 :                 get_time_str(thread_info->idle, idle_time);
    2416                 :          0 :                 mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 32, "%s", idle_time);
    2417                 :          0 :                 get_time_str(thread_info->busy, busy_time);
    2418                 :          0 :                 mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 54, "%s", busy_time);
    2419                 :            :         }
    2420                 :            : 
    2421                 :          0 :         print_left(thread_win, 4, THREAD_WIN_FIRST_COL, THREAD_WIN_WIDTH,
    2422                 :            :                    "Active pollers:      Timed pollers:        Paused pollers:", COLOR_PAIR(5));
    2423                 :          0 :         mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 17, "%" PRIu64,
    2424                 :            :                   thread_info->active_pollers_count);
    2425                 :          0 :         mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 36, "%" PRIu64,
    2426                 :            :                   thread_info->timed_pollers_count);
    2427                 :          0 :         mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 59, "%" PRIu64,
    2428                 :            :                   thread_info->paused_pollers_count);
    2429                 :            : 
    2430         [ #  # ]:          0 :         mvwhline(thread_win, 5, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
    2431                 :            : 
    2432                 :          0 :         print_in_middle(thread_win, 6, 0, THREAD_WIN_WIDTH,
    2433                 :            :                         "Pollers                          Type    Total run count   Period", COLOR_PAIR(5));
    2434                 :            : 
    2435         [ #  # ]:          0 :         mvwhline(thread_win, 7, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
    2436                 :            : 
    2437                 :          0 :         current_row = 8;
    2438                 :            : 
    2439         [ #  # ]:          0 :         for (i = 0; i < g_last_pollers_count; i++) {
    2440         [ #  # ]:          0 :                 if (g_pollers_info[i].thread_id == thread_info->id) {
    2441                 :          0 :                         mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL, "%s", g_pollers_info[i].name);
    2442         [ #  # ]:          0 :                         if (g_pollers_info[i].type == SPDK_ACTIVE_POLLER) {
    2443                 :          0 :                                 mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Active");
    2444         [ #  # ]:          0 :                         } else if (g_pollers_info[i].type == SPDK_TIMED_POLLER) {
    2445                 :          0 :                                 mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Timed");
    2446                 :            :                         } else {
    2447                 :          0 :                                 mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Paused");
    2448                 :            :                         }
    2449                 :          0 :                         mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 41, "%" PRIu64,
    2450                 :          0 :                                   g_pollers_info[i].run_count);
    2451         [ #  # ]:          0 :                         if (g_pollers_info[i].period_ticks) {
    2452         [ #  # ]:          0 :                                 time = g_pollers_info[i].period_ticks * SPDK_SEC_TO_USEC / g_tick_rate;
    2453                 :          0 :                                 mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 59, "%" PRIu64, time);
    2454                 :            :                         }
    2455                 :          0 :                         current_row++;
    2456                 :            :                 }
    2457                 :            :         }
    2458                 :            : 
    2459                 :          0 :         wnoutrefresh(thread_win);
    2460                 :          0 : }
    2461                 :            : 
    2462                 :            : static int
    2463                 :          0 : get_single_thread_info(uint64_t thread_id, struct rpc_thread_info *thread_info)
    2464                 :            : {
    2465                 :            :         uint64_t i;
    2466                 :            : 
    2467         [ #  # ]:          0 :         for (i = 0; i < g_last_threads_count; i++) {
    2468         [ #  # ]:          0 :                 if (g_threads_info[i].id == thread_id) {
    2469   [ #  #  #  # ]:          0 :                         memcpy(thread_info, &g_threads_info[i], sizeof(struct rpc_thread_info));
    2470         [ #  # ]:          0 :                         thread_info->name = strdup(g_threads_info[i].name);
    2471         [ #  # ]:          0 :                         thread_info->cpumask = strdup(g_threads_info[i].cpumask);
    2472                 :            : 
    2473   [ #  #  #  # ]:          0 :                         if (thread_info->name == NULL || thread_info->cpumask == NULL) {
    2474                 :          0 :                                 print_bottom_message("Unable to allocate memory for thread name and cpumask. Exiting pop-up.");
    2475                 :          0 :                                 return -1;
    2476                 :            :                         }
    2477                 :            : 
    2478                 :          0 :                         return 0;
    2479                 :            :                 }
    2480                 :            :         }
    2481                 :            : 
    2482                 :          0 :         print_bottom_message("Selected thread no longer exists. Exiting pop-up.");
    2483                 :          0 :         return -1;
    2484                 :            : }
    2485                 :            : 
    2486                 :            : static void
    2487                 :          0 : draw_core_win_content(WINDOW *core_win, struct rpc_core_info *core_info)
    2488                 :            : {
    2489                 :            :         uint64_t i;
    2490                 :          0 :         char core_win_title[25];
    2491                 :          0 :         char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];
    2492                 :            : 
    2493                 :          0 :         box(core_win, 0, 0);
    2494         [ #  # ]:          0 :         snprintf(core_win_title, sizeof(core_win_title), "Core %" PRIu32 " details",
    2495                 :            :                  core_info->lcore);
    2496                 :          0 :         print_in_middle(core_win, 1, 0, CORE_WIN_WIDTH, core_win_title, COLOR_PAIR(3));
    2497                 :            : 
    2498         [ #  # ]:          0 :         mvwhline(core_win, 2, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
    2499                 :          0 :         print_left(core_win, 3, 1, CORE_WIN_WIDTH - (CORE_WIN_WIDTH / 3),
    2500                 :            :                    "Frequency:             Intr:", COLOR_PAIR(5));
    2501         [ #  # ]:          0 :         if (core_info->core_freq) {
    2502                 :          0 :                 mvwprintw(core_win, 3, CORE_WIN_FIRST_COL - 3, "%" PRIu32,
    2503                 :            :                           core_info->core_freq);
    2504                 :            :         } else {
    2505                 :          0 :                 mvwprintw(core_win, 3, CORE_WIN_FIRST_COL - 3, "%s", "N/A");
    2506                 :            :         }
    2507                 :            : 
    2508                 :          0 :         mvwprintw(core_win, 3, CORE_WIN_FIRST_COL + 15, "%s",
    2509   [ #  #  #  # ]:          0 :                   core_info->in_interrupt ? "Yes" : "No");
    2510                 :            : 
    2511         [ #  # ]:          0 :         mvwhline(core_win, 4, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
    2512                 :          0 :         print_left(core_win, 5, 1, CORE_WIN_WIDTH, "Thread count:          Idle time:", COLOR_PAIR(5));
    2513                 :            : 
    2514                 :          0 :         mvwprintw(core_win, 5, CORE_WIN_FIRST_COL, "%" PRIu64,
    2515                 :            :                   core_info->threads.threads_count);
    2516                 :            : 
    2517   [ #  #  #  # ]:          0 :         if (g_interval_data == true) {
    2518                 :          0 :                 get_time_str(core_info->idle - core_info->last_idle, idle_time);
    2519                 :          0 :                 get_time_str(core_info->busy - core_info->last_busy, busy_time);
    2520                 :            :         } else {
    2521                 :          0 :                 get_time_str(core_info->idle, idle_time);
    2522                 :          0 :                 get_time_str(core_info->busy, busy_time);
    2523                 :            :         }
    2524                 :          0 :         mvwprintw(core_win, 5, CORE_WIN_FIRST_COL + 20, "%s", idle_time);
    2525         [ #  # ]:          0 :         mvwhline(core_win, 6, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
    2526                 :            : 
    2527                 :          0 :         print_left(core_win, 7, 1, CORE_WIN_WIDTH, "Poller count:          Busy time:", COLOR_PAIR(5));
    2528                 :          0 :         mvwprintw(core_win, 7, CORE_WIN_FIRST_COL, "%" PRIu64,
    2529                 :            :                   core_info->pollers_count);
    2530                 :            : 
    2531                 :          0 :         mvwprintw(core_win, 7, CORE_WIN_FIRST_COL + 20, "%s", busy_time);
    2532                 :            : 
    2533         [ #  # ]:          0 :         mvwhline(core_win, 8, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
    2534                 :          0 :         print_left(core_win, 9, 1, CORE_WIN_WIDTH, "Threads on this core", COLOR_PAIR(5));
    2535                 :            : 
    2536         [ #  # ]:          0 :         for (i = 0; i < core_info->threads.threads_count; i++) {
    2537                 :          0 :                 mvwprintw(core_win, i + CORE_WIN_HEIGHT - 1, 1, "%s", core_info->threads.thread[i].name);
    2538                 :            :         }
    2539         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    2540                 :            : 
    2541                 :          0 :         wnoutrefresh(core_win);
    2542                 :          0 : }
    2543                 :            : 
    2544                 :            : static void
    2545                 :          0 : display_thread(uint64_t thread_id, uint8_t current_page, uint8_t active_tab,
    2546                 :            :                WINDOW *core_popup, struct rpc_core_info *core_info)
    2547                 :            : {
    2548                 :          0 :         PANEL *thread_panel = NULL;
    2549                 :          0 :         WINDOW *thread_win = NULL;
    2550                 :          0 :         struct rpc_thread_info thread_info;
    2551                 :          0 :         uint64_t pollers_count, threads_count, last_pollers_count = 0;
    2552                 :            :         int c;
    2553                 :          0 :         bool stop_loop = false;
    2554                 :            :         long int time_last, time_dif;
    2555                 :          0 :         struct timespec time_now;
    2556                 :            : 
    2557         [ #  # ]:          0 :         clock_gettime(CLOCK_MONOTONIC, &time_now);
    2558                 :          0 :         time_last = time_now.tv_sec;
    2559                 :            : 
    2560         [ #  # ]:          0 :         memset(&thread_info, 0, sizeof(thread_info));
    2561                 :            : 
    2562         [ #  # ]:          0 :         while (!stop_loop) {
    2563         [ #  # ]:          0 :                 pthread_mutex_lock(&g_thread_lock);
    2564         [ #  # ]:          0 :                 if (get_single_thread_info(thread_id, &thread_info)) {
    2565         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2566                 :          0 :                         free(thread_info.name);
    2567                 :          0 :                         free(thread_info.cpumask);
    2568                 :          0 :                         thread_info.name = NULL;
    2569                 :          0 :                         thread_info.cpumask = NULL;
    2570                 :          0 :                         return;
    2571                 :            :                 }
    2572                 :          0 :                 pollers_count = thread_info.active_pollers_count +
    2573                 :          0 :                                 thread_info.timed_pollers_count +
    2574                 :          0 :                                 thread_info.paused_pollers_count;
    2575         [ #  # ]:          0 :                 if (pollers_count != last_pollers_count) {
    2576         [ #  # ]:          0 :                         if (thread_win != NULL) {
    2577         [ #  # ]:          0 :                                 assert(thread_panel != NULL);
    2578                 :          0 :                                 del_panel(thread_panel);
    2579                 :          0 :                                 delwin(thread_win);
    2580                 :            :                         }
    2581                 :            : 
    2582                 :          0 :                         thread_win = newwin(pollers_count + THREAD_WIN_HEIGHT, THREAD_WIN_WIDTH,
    2583                 :          0 :                                             get_position_for_window(THREAD_WIN_HEIGHT + pollers_count, g_max_row),
    2584                 :          0 :                                             get_position_for_window(THREAD_WIN_WIDTH, g_max_col));
    2585                 :          0 :                         keypad(thread_win, TRUE);
    2586                 :          0 :                         thread_panel = new_panel(thread_win);
    2587                 :            : 
    2588                 :          0 :                         top_panel(thread_panel);
    2589                 :          0 :                         update_panels();
    2590                 :          0 :                         doupdate();
    2591                 :          0 :                         draw_thread_win_content(thread_win, &thread_info);
    2592                 :          0 :                         refresh();
    2593                 :            :                 }
    2594         [ #  # ]:          0 :                 pthread_mutex_unlock(&g_thread_lock);
    2595                 :            : 
    2596         [ #  # ]:          0 :                 if (check_resize_interface(active_tab, &current_page)) {
    2597                 :            :                         /* This clear is to avoid remaining artifacts after window has been moved */
    2598                 :          0 :                         wclear(thread_win);
    2599                 :          0 :                         wclear(core_popup);
    2600                 :          0 :                         resize_interface(active_tab);
    2601                 :          0 :                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    2602         [ #  # ]:          0 :                         if (core_popup != NULL) {
    2603         [ #  # ]:          0 :                                 pthread_mutex_lock(&g_thread_lock);
    2604                 :          0 :                                 threads_count = g_cores_info[core_info->lcore].threads.threads_count;
    2605         [ #  # ]:          0 :                                 pthread_mutex_unlock(&g_thread_lock);
    2606                 :          0 :                                 mvwin(core_popup, get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
    2607                 :          0 :                                       get_position_for_window(CORE_WIN_WIDTH, g_max_col));
    2608                 :            :                         }
    2609                 :          0 :                         mvwin(thread_win, get_position_for_window(THREAD_WIN_HEIGHT + pollers_count, g_max_row),
    2610                 :          0 :                               get_position_for_window(THREAD_WIN_WIDTH, g_max_col));
    2611                 :            :                 }
    2612                 :            : 
    2613                 :          0 :                 c = getch();
    2614                 :            : 
    2615         [ #  # ]:          0 :                 switch (c) {
    2616                 :          0 :                 case 27: /* ESC */
    2617                 :          0 :                         stop_loop = true;
    2618                 :          0 :                         break;
    2619                 :          0 :                 default:
    2620                 :          0 :                         break;
    2621                 :            :                 }
    2622                 :            : 
    2623         [ #  # ]:          0 :                 clock_gettime(CLOCK_MONOTONIC, &time_now);
    2624                 :          0 :                 time_dif = time_now.tv_sec - time_last;
    2625                 :            : 
    2626         [ #  # ]:          0 :                 if (time_dif >= g_sleep_time) {
    2627                 :          0 :                         time_last = time_now.tv_sec;
    2628         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2629                 :          0 :                         refresh_tab(active_tab, current_page);
    2630         [ #  # ]:          0 :                         if (core_popup != NULL) {
    2631                 :          0 :                                 draw_core_win_content(core_popup, core_info);
    2632                 :            :                         }
    2633                 :          0 :                         draw_thread_win_content(thread_win, &thread_info);
    2634                 :          0 :                         refresh();
    2635         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2636                 :            :                 }
    2637                 :            : 
    2638                 :          0 :                 last_pollers_count = pollers_count;
    2639                 :          0 :                 free(thread_info.name);
    2640                 :          0 :                 free(thread_info.cpumask);
    2641                 :          0 :                 thread_info.name = NULL;
    2642                 :          0 :                 thread_info.cpumask = NULL;
    2643                 :            :         }
    2644                 :            : 
    2645                 :          0 :         del_panel(thread_panel);
    2646                 :          0 :         delwin(thread_win);
    2647                 :            : }
    2648                 :            : 
    2649                 :            : static void
    2650                 :          0 : show_thread(uint8_t current_page, uint8_t active_tab)
    2651                 :            : {
    2652                 :          0 :         uint64_t thread_number = current_page * g_max_data_rows + g_selected_row;
    2653                 :            :         uint64_t thread_id;
    2654                 :            : 
    2655         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    2656         [ #  # ]:          0 :         assert(thread_number < g_last_threads_count);
    2657                 :          0 :         thread_id = g_threads_info[thread_number].id;
    2658         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    2659                 :            : 
    2660                 :          0 :         display_thread(thread_id, current_page, active_tab, NULL, NULL);
    2661                 :          0 : }
    2662                 :            : 
    2663                 :            : static void
    2664                 :          0 : show_single_thread(uint64_t thread_id, uint8_t current_page, uint8_t active_tab, WINDOW *core_popup,
    2665                 :            :                    struct rpc_core_info *core_info)
    2666                 :            : {
    2667                 :            :         uint64_t i;
    2668                 :            : 
    2669         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    2670         [ #  # ]:          0 :         for (i = 0; i < g_last_threads_count; i++) {
    2671         [ #  # ]:          0 :                 if (g_threads_info[i].id == thread_id) {
    2672         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2673                 :          0 :                         display_thread(thread_id, current_page, active_tab, core_popup, core_info);
    2674                 :          0 :                         return;
    2675                 :            :                 }
    2676                 :            :         }
    2677         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    2678                 :            : }
    2679                 :            : 
    2680                 :            : static void
    2681                 :          0 : show_core(uint8_t current_page, uint8_t active_tab)
    2682                 :            : {
    2683                 :            :         PANEL *core_panel;
    2684                 :            :         WINDOW *core_win;
    2685                 :          0 :         uint64_t core_number = current_page * g_max_data_rows + g_selected_row;
    2686                 :          0 :         struct rpc_core_info *core_info = &g_cores_info[core_number];
    2687                 :            :         uint64_t threads_count, i;
    2688                 :          0 :         uint64_t thread_id = 0;
    2689                 :            :         uint16_t current_threads_row;
    2690                 :            :         int c;
    2691                 :            :         long int time_last, time_dif;
    2692                 :          0 :         struct timespec time_now;
    2693                 :            : 
    2694         [ #  # ]:          0 :         clock_gettime(CLOCK_MONOTONIC, &time_now);
    2695                 :          0 :         time_last = time_now.tv_sec;
    2696                 :            : 
    2697                 :          0 :         bool stop_loop = false;
    2698                 :            : 
    2699         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    2700         [ #  # ]:          0 :         assert(core_number < g_last_cores_count);
    2701                 :            : 
    2702                 :          0 :         threads_count = g_cores_info[core_number].threads.threads_count;
    2703                 :            : 
    2704                 :          0 :         core_win = newwin(threads_count + CORE_WIN_HEIGHT, CORE_WIN_WIDTH,
    2705                 :          0 :                           get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
    2706                 :          0 :                           get_position_for_window(CORE_WIN_WIDTH, g_max_col));
    2707                 :            : 
    2708                 :          0 :         keypad(core_win, TRUE);
    2709                 :          0 :         core_panel = new_panel(core_win);
    2710                 :            : 
    2711                 :          0 :         top_panel(core_panel);
    2712                 :          0 :         update_panels();
    2713                 :          0 :         doupdate();
    2714                 :          0 :         draw_core_win_content(core_win, core_info);
    2715                 :          0 :         refresh();
    2716                 :            : 
    2717                 :          0 :         current_threads_row = 0;
    2718                 :            : 
    2719         [ #  # ]:          0 :         while (!stop_loop) {
    2720         [ #  # ]:          0 :                 pthread_mutex_lock(&g_thread_lock);
    2721         [ #  # ]:          0 :                 for (i = 0; i < core_info->threads.threads_count; i++) {
    2722         [ #  # ]:          0 :                         if (i != current_threads_row) {
    2723                 :          0 :                                 mvwprintw(core_win, i + CORE_WIN_HEIGHT - 1, 1,
    2724                 :          0 :                                           "%s", core_info->threads.thread[i].name);
    2725                 :            :                         } else {
    2726                 :          0 :                                 print_left(core_win, i + CORE_WIN_HEIGHT - 1, 1, CORE_WIN_WIDTH - 2,
    2727                 :          0 :                                            core_info->threads.thread[i].name, COLOR_PAIR(2));
    2728                 :            :                         }
    2729                 :            :                 }
    2730         [ #  # ]:          0 :                 pthread_mutex_unlock(&g_thread_lock);
    2731                 :            : 
    2732                 :          0 :                 wrefresh(core_win);
    2733         [ #  # ]:          0 :                 if (check_resize_interface(active_tab, &current_page)) {
    2734                 :          0 :                         wclear(core_win);
    2735                 :          0 :                         resize_interface(active_tab);
    2736                 :          0 :                         draw_tab_win(active_tab);
    2737                 :          0 :                         mvwin(core_win, get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
    2738                 :          0 :                               get_position_for_window(CORE_WIN_WIDTH, g_max_col));
    2739                 :            :                 }
    2740                 :            : 
    2741                 :          0 :                 c = getch();
    2742   [ #  #  #  #  :          0 :                 switch (c) {
                      # ]
    2743                 :          0 :                 case 10: /* ENTER */
    2744         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2745         [ #  # ]:          0 :                         if (core_info->threads.threads_count > 0) {
    2746                 :          0 :                                 thread_id = core_info->threads.thread[current_threads_row].id;
    2747                 :            :                         }
    2748         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2749                 :            : 
    2750         [ #  # ]:          0 :                         if (thread_id != 0) {
    2751                 :          0 :                                 show_single_thread(thread_id, current_page, active_tab, core_win, core_info);
    2752                 :            :                         }
    2753                 :            : 
    2754                 :            :                         /* This refreshes tab and core_pop-up after exiting threads pop-up. */
    2755         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2756                 :          0 :                         refresh_tab(active_tab, current_page);
    2757                 :          0 :                         wnoutrefresh(core_win);
    2758                 :          0 :                         refresh();
    2759         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2760                 :          0 :                         break;
    2761                 :          0 :                 case 27: /* ESC */
    2762                 :          0 :                         stop_loop = true;
    2763                 :          0 :                         break;
    2764                 :          0 :                 case KEY_UP:
    2765         [ #  # ]:          0 :                         if (current_threads_row != 0) {
    2766                 :          0 :                                 current_threads_row--;
    2767                 :            :                         }
    2768                 :          0 :                         break;
    2769                 :          0 :                 case KEY_DOWN:
    2770         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2771         [ #  # ]:          0 :                         if (current_threads_row != core_info->threads.threads_count - 1) {
    2772                 :          0 :                                 current_threads_row++;
    2773                 :            :                         }
    2774         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2775                 :          0 :                         break;
    2776                 :          0 :                 default:
    2777                 :          0 :                         break;
    2778                 :            :                 }
    2779                 :            : 
    2780         [ #  # ]:          0 :                 clock_gettime(CLOCK_MONOTONIC, &time_now);
    2781                 :          0 :                 time_dif = time_now.tv_sec - time_last;
    2782                 :            : 
    2783         [ #  # ]:          0 :                 if (time_dif >= g_sleep_time) {
    2784                 :          0 :                         time_last = time_now.tv_sec;
    2785         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2786                 :          0 :                         refresh_tab(active_tab, current_page);
    2787                 :          0 :                         draw_core_win_content(core_win, core_info);
    2788                 :          0 :                         refresh();
    2789         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2790                 :            :                 }
    2791                 :            :         }
    2792                 :            : 
    2793                 :          0 :         del_panel(core_panel);
    2794                 :          0 :         delwin(core_win);
    2795                 :          0 : }
    2796                 :            : 
    2797                 :            : static void
    2798                 :          0 : draw_poller_win_content(WINDOW *poller_win, struct rpc_poller_info *poller_info)
    2799                 :            : {
    2800                 :            :         uint64_t last_run_counter, last_busy_counter, busy_count;
    2801                 :          0 :         char poller_period[MAX_TIME_STR_LEN];
    2802                 :            : 
    2803                 :          0 :         box(poller_win, 0, 0);
    2804                 :            : 
    2805                 :          0 :         print_in_middle(poller_win, 1, 0, POLLER_WIN_WIDTH, poller_info->name, COLOR_PAIR(3));
    2806         [ #  # ]:          0 :         mvwhline(poller_win, 2, 1, ACS_HLINE, POLLER_WIN_WIDTH - 2);
    2807         [ #  # ]:          0 :         mvwaddch(poller_win, 2, POLLER_WIN_WIDTH, ACS_RTEE);
    2808                 :            : 
    2809                 :          0 :         print_left(poller_win, 3, 2, POLLER_WIN_WIDTH, "Type:                  On thread:", COLOR_PAIR(5));
    2810                 :          0 :         mvwprintw(poller_win, 3, POLLER_WIN_FIRST_COL, "%s",
    2811                 :          0 :                   poller_type_str[poller_info->type]);
    2812                 :          0 :         mvwprintw(poller_win, 3, POLLER_WIN_FIRST_COL + 23, "%s", poller_info->thread_name);
    2813                 :            : 
    2814                 :          0 :         print_left(poller_win, 4, 2, POLLER_WIN_WIDTH, "Run count:", COLOR_PAIR(5));
    2815                 :            : 
    2816                 :          0 :         last_run_counter = get_last_run_counter(poller_info->id, poller_info->thread_id);
    2817                 :          0 :         last_busy_counter = get_last_busy_counter(poller_info->id, poller_info->thread_id);
    2818   [ #  #  #  # ]:          0 :         if (g_interval_data) {
    2819                 :          0 :                 mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL, "%" PRIu64,
    2820                 :          0 :                           poller_info->run_count - last_run_counter);
    2821                 :            :         } else {
    2822                 :          0 :                 mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL, "%" PRIu64, poller_info->run_count);
    2823                 :            :         }
    2824                 :            : 
    2825         [ #  # ]:          0 :         if (poller_info->period_ticks != 0) {
    2826                 :          0 :                 print_left(poller_win, 4, 28, POLLER_WIN_WIDTH, "Period:", COLOR_PAIR(5));
    2827                 :          0 :                 get_time_str(poller_info->period_ticks, poller_period);
    2828                 :          0 :                 mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL + 23, "%s", poller_period);
    2829                 :            :         }
    2830         [ #  # ]:          0 :         mvwhline(poller_win, 5, 1, ACS_HLINE, POLLER_WIN_WIDTH - 2);
    2831                 :            : 
    2832   [ #  #  #  # ]:          0 :         busy_count = g_interval_data ? poller_info->busy_count - last_busy_counter :
    2833                 :            :                      poller_info->busy_count;
    2834         [ #  # ]:          0 :         if (busy_count != 0) {
    2835                 :          0 :                 print_left(poller_win, 6, 2, POLLER_WIN_WIDTH,  "Status:               Busy count:", COLOR_PAIR(5));
    2836                 :            : 
    2837   [ #  #  #  #  :          0 :                 if (g_interval_data == false && poller_info->busy_count == last_busy_counter) {
                   #  # ]
    2838                 :          0 :                         print_left(poller_win, 6, POLLER_WIN_FIRST_COL, POLLER_WIN_WIDTH, "Idle", COLOR_PAIR(7));
    2839                 :            :                 } else {
    2840                 :          0 :                         print_left(poller_win, 6, POLLER_WIN_FIRST_COL, POLLER_WIN_WIDTH, "Busy", COLOR_PAIR(6));
    2841                 :            :                 }
    2842                 :            : 
    2843                 :          0 :                 mvwprintw(poller_win, 6, POLLER_WIN_FIRST_COL + 23, "%" PRIu64, busy_count);
    2844                 :            :         } else {
    2845                 :          0 :                 print_in_middle(poller_win, 6, 1, POLLER_WIN_WIDTH - 7, "Status:", COLOR_PAIR(5));
    2846                 :          0 :                 print_in_middle(poller_win, 6, 1, POLLER_WIN_WIDTH + 6, "Idle", COLOR_PAIR(7));
    2847                 :            :         }
    2848                 :            : 
    2849                 :          0 :         wnoutrefresh(poller_win);
    2850                 :          0 : }
    2851                 :            : 
    2852                 :            : static void
    2853                 :          0 : show_poller(uint8_t current_page, uint8_t active_tab)
    2854                 :            : {
    2855                 :            :         PANEL *poller_panel;
    2856                 :            :         WINDOW *poller_win;
    2857                 :          0 :         uint64_t poller_number = current_page * g_max_data_rows + g_selected_row;
    2858                 :            :         struct rpc_poller_info *poller;
    2859                 :          0 :         bool stop_loop = false;
    2860                 :            :         int c;
    2861                 :            :         long int time_last, time_dif;
    2862                 :          0 :         struct timespec time_now;
    2863                 :            : 
    2864         [ #  # ]:          0 :         clock_gettime(CLOCK_MONOTONIC, &time_now);
    2865                 :          0 :         time_last = time_now.tv_sec;
    2866                 :            : 
    2867                 :            : 
    2868         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    2869                 :            : 
    2870         [ #  # ]:          0 :         assert(poller_number < g_last_pollers_count);
    2871                 :          0 :         poller = &g_pollers_info[poller_number];
    2872                 :            : 
    2873                 :          0 :         poller_win = newwin(POLLER_WIN_HEIGHT, POLLER_WIN_WIDTH,
    2874                 :          0 :                             get_position_for_window(POLLER_WIN_HEIGHT, g_max_row),
    2875                 :          0 :                             get_position_for_window(POLLER_WIN_WIDTH, g_max_col));
    2876                 :            : 
    2877                 :          0 :         keypad(poller_win, TRUE);
    2878                 :          0 :         poller_panel = new_panel(poller_win);
    2879                 :            : 
    2880                 :          0 :         top_panel(poller_panel);
    2881                 :          0 :         update_panels();
    2882                 :          0 :         doupdate();
    2883                 :          0 :         draw_poller_win_content(poller_win, poller);
    2884                 :          0 :         refresh();
    2885                 :            : 
    2886         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    2887         [ #  # ]:          0 :         while (!stop_loop) {
    2888         [ #  # ]:          0 :                 if (check_resize_interface(active_tab, &current_page)) {
    2889                 :            :                         /* This clear is to avoid remaining artifacts after window has been moved */
    2890                 :          0 :                         wclear(poller_win);
    2891                 :          0 :                         resize_interface(active_tab);
    2892                 :          0 :                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    2893                 :          0 :                         mvwin(poller_win, get_position_for_window(POLLER_WIN_HEIGHT, g_max_row),
    2894                 :          0 :                               get_position_for_window(POLLER_WIN_WIDTH, g_max_col));
    2895                 :            :                 }
    2896                 :          0 :                 c = getch();
    2897         [ #  # ]:          0 :                 switch (c) {
    2898                 :          0 :                 case 27: /* ESC */
    2899                 :          0 :                         stop_loop = true;
    2900                 :          0 :                         break;
    2901                 :          0 :                 default:
    2902                 :          0 :                         break;
    2903                 :            :                 }
    2904                 :            : 
    2905         [ #  # ]:          0 :                 clock_gettime(CLOCK_MONOTONIC, &time_now);
    2906                 :          0 :                 time_dif = time_now.tv_sec - time_last;
    2907                 :            : 
    2908         [ #  # ]:          0 :                 if (time_dif >= g_sleep_time) {
    2909                 :          0 :                         time_last = time_now.tv_sec;
    2910         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    2911                 :          0 :                         refresh_tab(active_tab, current_page);
    2912                 :          0 :                         draw_poller_win_content(poller_win, poller);
    2913                 :          0 :                         refresh();
    2914         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    2915                 :            :                 }
    2916                 :            :         }
    2917                 :            : 
    2918                 :          0 :         del_panel(poller_panel);
    2919                 :          0 :         delwin(poller_win);
    2920                 :          0 : }
    2921                 :            : 
    2922                 :            : static uint64_t
    2923                 :          0 : get_max_scheduler_win_width(uint8_t sched_name_label_len, uint8_t sched_period_label_len,
    2924                 :            :                             uint8_t gov_name_label_len)
    2925                 :            : {
    2926                 :          0 :         uint8_t window_borders = 4;
    2927                 :            :         uint64_t s_name, s_period, g_name, max_name_len;
    2928                 :          0 :         char scheduler_period[MAX_SCHEDULER_PERIOD_STR_LEN];
    2929                 :            : 
    2930                 :          0 :         snprintf(scheduler_period, MAX_SCHEDULER_PERIOD_STR_LEN, "%" PRIu64,
    2931                 :            :                  g_scheduler_info.scheduler_period);
    2932                 :            : 
    2933         [ #  # ]:          0 :         s_name = strlen(g_scheduler_info.scheduler_name) + sched_name_label_len;
    2934         [ #  # ]:          0 :         if (g_scheduler_info.governor_name != NULL) {
    2935         [ #  # ]:          0 :                 g_name = strlen(g_scheduler_info.governor_name) + gov_name_label_len;
    2936                 :            :         } else {
    2937                 :          0 :                 g_name = strlen("none") + gov_name_label_len;
    2938                 :            :         }
    2939                 :          0 :         s_period = strlen(scheduler_period) + sched_period_label_len;
    2940                 :            : 
    2941                 :          0 :         max_name_len = spdk_max(s_name, g_name);
    2942                 :            :         /* This function relies on the fact that scheduler/governor
    2943                 :            :          * names will not change during runtime. Otherwise the scheduler
    2944                 :            :          * pop-up would need dynamic resizing. */
    2945                 :            : 
    2946                 :          0 :         return spdk_max(max_name_len, s_period) + window_borders;
    2947                 :            : }
    2948                 :            : 
    2949                 :            : static void
    2950                 :          0 : draw_scheduler_popup(WINDOW *scheduler_win, uint64_t scheduler_win_width, uint8_t active_tab,
    2951                 :            :                      uint8_t current_page, const char *scheduler_name_label,
    2952                 :            :                      const char *scheduler_period_label, const char *governor_name_label)
    2953                 :            : {
    2954                 :          0 :         char scheduler_period[MAX_SCHEDULER_PERIOD_STR_LEN];
    2955                 :            : 
    2956                 :          0 :         box(scheduler_win, 0, 0);
    2957                 :            : 
    2958                 :          0 :         print_left(scheduler_win, 1, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, scheduler_name_label,
    2959                 :            :                    COLOR_PAIR(5));
    2960                 :          0 :         print_left(scheduler_win, 1, SCHEDULER_WIN_FIRST_COL + strlen(scheduler_name_label),
    2961                 :            :                    scheduler_win_width,
    2962         [ #  # ]:          0 :                    g_scheduler_info.scheduler_name, COLOR_PAIR(3));
    2963                 :            : 
    2964         [ #  # ]:          0 :         mvwhline(scheduler_win, 2, 1, ACS_HLINE, scheduler_win_width - 2);
    2965         [ #  # ]:          0 :         mvwaddch(scheduler_win, 2, scheduler_win_width, ACS_RTEE);
    2966                 :            : 
    2967                 :          0 :         print_left(scheduler_win, 3, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, scheduler_period_label,
    2968                 :            :                    COLOR_PAIR(5));
    2969                 :          0 :         snprintf(scheduler_period, MAX_SCHEDULER_PERIOD_STR_LEN, "%" PRIu64,
    2970                 :            :                  g_scheduler_info.scheduler_period);
    2971         [ #  # ]:          0 :         mvwprintw(scheduler_win, 3, SCHEDULER_WIN_FIRST_COL + strlen(scheduler_period_label), "%s",
    2972                 :            :                   scheduler_period);
    2973                 :            : 
    2974         [ #  # ]:          0 :         mvwhline(scheduler_win, 4, 1, ACS_HLINE, scheduler_win_width - 2);
    2975         [ #  # ]:          0 :         mvwaddch(scheduler_win, 4, scheduler_win_width, ACS_RTEE);
    2976                 :            : 
    2977                 :          0 :         print_left(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, governor_name_label,
    2978                 :            :                    COLOR_PAIR(5));
    2979                 :            : 
    2980         [ #  # ]:          0 :         if (g_scheduler_info.governor_name != NULL) {
    2981         [ #  # ]:          0 :                 mvwprintw(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL + strlen(governor_name_label), "%s",
    2982                 :            :                           g_scheduler_info.governor_name);
    2983                 :            :         } else {
    2984         [ #  # ]:          0 :                 mvwprintw(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL + strlen(governor_name_label), "%s", "none");
    2985                 :            :         }
    2986                 :            : 
    2987                 :          0 :         refresh_tab(active_tab, current_page);
    2988                 :          0 :         wnoutrefresh(scheduler_win);
    2989                 :          0 :         refresh();
    2990                 :          0 : }
    2991                 :            : 
    2992                 :            : static void
    2993                 :          0 : show_scheduler(uint8_t active_tab, uint8_t current_page)
    2994                 :            : {
    2995                 :            :         PANEL *scheduler_panel;
    2996                 :            :         WINDOW *scheduler_win;
    2997                 :            :         uint64_t scheduler_win_width;
    2998                 :          0 :         bool stop_loop = false;
    2999                 :            :         int c;
    3000                 :          0 :         const char *scheduler_name_label = "Scheduler:  ";
    3001                 :          0 :         const char *scheduler_period_label = "Period [us]:  ";
    3002                 :          0 :         const char *governor_name_label = "Governor:  ";
    3003                 :            : 
    3004                 :          0 :         pthread_mutex_lock(&g_thread_lock);
    3005                 :          0 :         scheduler_win_width = get_max_scheduler_win_width(strlen(scheduler_name_label),
    3006         [ #  # ]:          0 :                               strlen(scheduler_period_label),
    3007   [ #  #  #  # ]:          0 :                               strlen(governor_name_label));
    3008                 :            : 
    3009                 :          0 :         scheduler_win = newwin(SCHEDULER_WIN_HEIGHT, scheduler_win_width,
    3010                 :          0 :                                get_position_for_window(SCHEDULER_WIN_HEIGHT, g_max_row),
    3011                 :          0 :                                get_position_for_window(scheduler_win_width, g_max_col));
    3012                 :            : 
    3013                 :          0 :         keypad(scheduler_win, TRUE);
    3014                 :          0 :         scheduler_panel = new_panel(scheduler_win);
    3015                 :            : 
    3016                 :          0 :         top_panel(scheduler_panel);
    3017                 :          0 :         update_panels();
    3018                 :          0 :         doupdate();
    3019                 :            : 
    3020                 :          0 :         draw_scheduler_popup(scheduler_win, scheduler_win_width, active_tab, current_page,
    3021                 :            :                              scheduler_name_label, scheduler_period_label, governor_name_label);
    3022                 :          0 :         pthread_mutex_unlock(&g_thread_lock);
    3023                 :            : 
    3024         [ #  # ]:          0 :         while (!stop_loop) {
    3025                 :          0 :                 c = wgetch(scheduler_win);
    3026                 :            : 
    3027         [ #  # ]:          0 :                 switch (c) {
    3028                 :          0 :                 case 27: /* ESC */
    3029                 :          0 :                         stop_loop = true;
    3030                 :          0 :                         break;
    3031                 :          0 :                 default:
    3032                 :          0 :                         break;
    3033                 :            :                 }
    3034                 :            :         }
    3035                 :            : 
    3036                 :          0 :         del_panel(scheduler_panel);
    3037                 :          0 :         delwin(scheduler_win);
    3038                 :          0 : }
    3039                 :            : 
    3040                 :            : static void *
    3041                 :          0 : data_thread_routine(void *arg)
    3042                 :            : {
    3043                 :            :         int rc;
    3044                 :            :         uint64_t refresh_rate;
    3045                 :            : 
    3046                 :            :         while (1) {
    3047         [ #  # ]:          0 :                 pthread_mutex_lock(&g_thread_lock);
    3048   [ #  #  #  # ]:          0 :                 if (g_quit_app) {
    3049         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    3050                 :          0 :                         break;
    3051                 :            :                 }
    3052                 :            : 
    3053         [ #  # ]:          0 :                 if (g_sleep_time == 0) {
    3054                 :            :                         /* Give display thread time to redraw all windows */
    3055                 :          0 :                         refresh_rate = SPDK_SEC_TO_USEC / 100;
    3056                 :            :                 } else {
    3057                 :          0 :                         refresh_rate = g_sleep_time * SPDK_SEC_TO_USEC;
    3058                 :            :                 }
    3059         [ #  # ]:          0 :                 pthread_mutex_unlock(&g_thread_lock);
    3060                 :            : 
    3061                 :            :                 /* Get data from RPC for each object type.
    3062                 :            :                  * Start with cores since their number should not change. */
    3063                 :          0 :                 rc = get_cores_data();
    3064         [ #  # ]:          0 :                 if (rc) {
    3065                 :          0 :                         print_bottom_message("ERROR occurred while getting cores data");
    3066                 :            :                 }
    3067                 :          0 :                 rc = get_thread_data();
    3068         [ #  # ]:          0 :                 if (rc) {
    3069                 :          0 :                         print_bottom_message("ERROR occurred while getting threads data");
    3070                 :            :                 }
    3071                 :            : 
    3072                 :          0 :                 rc = get_pollers_data();
    3073         [ #  # ]:          0 :                 if (rc) {
    3074                 :          0 :                         print_bottom_message("ERROR occurred while getting pollers data");
    3075                 :            :                 }
    3076                 :          0 :                 rc = get_scheduler_data();
    3077         [ #  # ]:          0 :                 if (rc) {
    3078                 :          0 :                         print_bottom_message("ERROR occurred while getting scheduler data");
    3079                 :            :                 }
    3080                 :            : 
    3081                 :          0 :                 usleep(refresh_rate);
    3082                 :            :         }
    3083                 :            : 
    3084                 :          0 :         return NULL;
    3085                 :            : }
    3086                 :            : 
    3087                 :            : static void
    3088                 :          0 : help_window_display(void)
    3089                 :            : {
    3090                 :            :         PANEL *help_panel;
    3091                 :            :         WINDOW *help_win;
    3092                 :          0 :         bool stop_loop = false;
    3093                 :            :         int c;
    3094                 :          0 :         uint64_t row = 1, col = 2, desc_second_row_col = 26, header_footer_col = 0;
    3095                 :            : 
    3096                 :          0 :         help_win = newwin(HELP_WIN_HEIGHT, HELP_WIN_WIDTH,
    3097                 :          0 :                           get_position_for_window(HELP_WIN_HEIGHT, g_max_row),
    3098                 :          0 :                           get_position_for_window(HELP_WIN_WIDTH, g_max_col));
    3099                 :          0 :         help_panel = new_panel(help_win);
    3100                 :          0 :         top_panel(help_panel);
    3101                 :          0 :         update_panels();
    3102                 :          0 :         doupdate();
    3103                 :            : 
    3104                 :          0 :         box(help_win, 0, 0);
    3105                 :            : 
    3106                 :            :         /* Header */
    3107                 :          0 :         print_in_middle(help_win, row, header_footer_col, HELP_WIN_WIDTH, "HELP", COLOR_PAIR(3));
    3108         [ #  # ]:          0 :         mvwhline(help_win, 2, 1, ACS_HLINE, HELP_WIN_WIDTH - 2);
    3109         [ #  # ]:          0 :         mvwaddch(help_win, 2, HELP_WIN_WIDTH, ACS_RTEE);
    3110                 :          0 :         row = 3;
    3111                 :            : 
    3112                 :            :         /* Content */
    3113                 :          0 :         print_left(help_win, row, col, HELP_WIN_WIDTH, "MENU options", COLOR_PAIR(5));
    3114                 :          0 :         print_left(help_win, ++row, ++col, HELP_WIN_WIDTH, "[q] Quit               - quit this application",
    3115                 :            :                    COLOR_PAIR(10));
    3116                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3117                 :            :                    "[Tab] Next tab - switch to next tab", COLOR_PAIR(10));
    3118                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3119                 :            :                    "[1-3] Select tab       - switch to THREADS, POLLERS or CORES tab", COLOR_PAIR(10));
    3120                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3121                 :            :                    "[PgUp] Previous page   - scroll up to previous page", COLOR_PAIR(10));
    3122                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3123                 :            :                    "[PgDown] Next page     - scroll down to next page", COLOR_PAIR(10));
    3124                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3125                 :            :                    "[Up] Arrow key - go to previous data row", COLOR_PAIR(10));
    3126                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3127                 :            :                    "[Down] Arrow key       - go to next data row", COLOR_PAIR(10));
    3128                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3129                 :            :                    "[Right] Arrow key      - go to second sorting window", COLOR_PAIR(10));
    3130                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3131                 :            :                    "[Left] Arrow key       - close second sorting window", COLOR_PAIR(10));
    3132                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3133                 :            :                    "[c] Columns            - choose data columns to display", COLOR_PAIR(10));
    3134                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3135                 :            :                    "[s] Sorting            - change sorting by column", COLOR_PAIR(10));
    3136                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3137                 :            :                    "[r] Refresh rate       - set refresh rate <0, 255> in seconds", COLOR_PAIR(10));
    3138                 :          0 :         print_left(help_win, ++row, desc_second_row_col,  HELP_WIN_WIDTH, "that value in seconds",
    3139                 :            :                    COLOR_PAIR(10));
    3140                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3141                 :            :                    "[Enter] Item details   - show current data row details (Enter to open, Esc to close)",
    3142                 :            :                    COLOR_PAIR(10));
    3143                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3144                 :            :                    "[t] Total/Interval     - switch to display data measured from the start of SPDK", COLOR_PAIR(10));
    3145                 :          0 :         print_left(help_win, ++row, desc_second_row_col,  HELP_WIN_WIDTH,
    3146                 :            :                    "application or last refresh", COLOR_PAIR(10));
    3147                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH,
    3148                 :            :                    "[g] Scheduler pop-up - display current scheduler information", COLOR_PAIR(10));
    3149                 :          0 :         print_left(help_win, ++row, col,  HELP_WIN_WIDTH, "[h] Help                - show this help window",
    3150                 :            :                    COLOR_PAIR(10));
    3151                 :            : 
    3152                 :            :         /* Footer */
    3153         [ #  # ]:          0 :         mvwhline(help_win, HELP_WIN_HEIGHT - 3, 1, ACS_HLINE, HELP_WIN_WIDTH - 2);
    3154         [ #  # ]:          0 :         mvwaddch(help_win, HELP_WIN_HEIGHT - 3, HELP_WIN_WIDTH, ACS_RTEE);
    3155                 :            : 
    3156                 :          0 :         print_in_middle(help_win, HELP_WIN_HEIGHT - 2, header_footer_col, HELP_WIN_WIDTH,
    3157                 :            :                         "[Esc] Close this window", COLOR_PAIR(10));
    3158                 :            : 
    3159                 :          0 :         refresh();
    3160                 :          0 :         wrefresh(help_win);
    3161                 :            : 
    3162         [ #  # ]:          0 :         while (!stop_loop) {
    3163                 :          0 :                 c = wgetch(help_win);
    3164                 :            : 
    3165         [ #  # ]:          0 :                 switch (c) {
    3166                 :          0 :                 case 27: /* ESC */
    3167                 :          0 :                         stop_loop = true;
    3168                 :          0 :                         break;
    3169                 :          0 :                 default:
    3170                 :          0 :                         break;
    3171                 :            :                 }
    3172                 :            :         }
    3173                 :            : 
    3174                 :          0 :         del_panel(help_panel);
    3175                 :          0 :         delwin(help_win);
    3176                 :            : 
    3177                 :          0 : }
    3178                 :            : 
    3179                 :            : static void
    3180                 :          0 : refresh_after_popup(uint8_t active_tab, uint8_t *max_pages, uint8_t current_page)
    3181                 :            : {
    3182                 :            :         int i;
    3183                 :            : 
    3184                 :            :         /* After closing pop-up there would be unrefreshed parts
    3185                 :            :          * of the tab, so this is to refresh them */
    3186                 :          0 :         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    3187         [ #  # ]:          0 :         pthread_mutex_lock(&g_thread_lock);
    3188                 :          0 :         *max_pages = refresh_tab(active_tab, current_page);
    3189         [ #  # ]:          0 :         pthread_mutex_unlock(&g_thread_lock);
    3190                 :          0 :         top_panel(g_panels[active_tab]);
    3191                 :            : 
    3192         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    3193                 :          0 :                 wclear(g_tab_win[i]);
    3194                 :          0 :                 wresize(g_tab_win[i], TAB_WIN_HEIGHT,
    3195                 :          0 :                         (g_max_col - (TABS_SPACING * NUMBER_OF_TABS)) / NUMBER_OF_TABS);
    3196                 :          0 :                 mvwin(g_tab_win[i], TAB_WIN_LOCATION_ROW, 1 + (g_max_col / NUMBER_OF_TABS) * i);
    3197                 :          0 :                 draw_tab_win(i);
    3198                 :            :         }
    3199                 :            : 
    3200                 :          0 :         update_panels();
    3201                 :          0 :         refresh();
    3202                 :          0 : }
    3203                 :            : 
    3204                 :            : static void
    3205                 :          0 : show_stats(pthread_t *data_thread)
    3206                 :          0 : {
    3207                 :          0 :         const int CURRENT_PAGE_STR_LEN = 50;
    3208                 :            :         long int time_last, time_dif;
    3209                 :          0 :         struct timespec time_now;
    3210                 :            :         int c;
    3211                 :          0 :         uint8_t active_tab = THREADS_TAB;
    3212                 :          0 :         uint8_t current_page = 0;
    3213                 :          0 :         uint8_t max_pages = 1;
    3214                 :            :         uint64_t i;
    3215         [ #  # ]:          0 :         char current_page_str[CURRENT_PAGE_STR_LEN];
    3216                 :          0 :         bool force_refresh = true;
    3217                 :            : 
    3218         [ #  # ]:          0 :         clock_gettime(CLOCK_MONOTONIC, &time_now);
    3219                 :          0 :         time_last = time_now.tv_sec;
    3220                 :            : 
    3221                 :          0 :         switch_tab(THREADS_TAB);
    3222                 :            : 
    3223                 :            :         while (1) {
    3224                 :          0 :                 check_resize_interface(active_tab, &current_page);
    3225                 :            : 
    3226         [ #  # ]:          0 :                 clock_gettime(CLOCK_MONOTONIC, &time_now);
    3227                 :          0 :                 time_dif = time_now.tv_sec - time_last;
    3228         [ #  # ]:          0 :                 if (time_dif < 0) {
    3229                 :          0 :                         time_dif = g_sleep_time;
    3230                 :            :                 }
    3231                 :            : 
    3232   [ #  #  #  # ]:          0 :                 if (time_dif >= g_sleep_time || force_refresh) {
    3233                 :          0 :                         time_last = time_now.tv_sec;
    3234         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    3235                 :          0 :                         max_pages = refresh_tab(active_tab, current_page);
    3236         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    3237                 :            : 
    3238         [ #  # ]:          0 :                         snprintf(current_page_str, CURRENT_PAGE_STR_LEN - 1, "Page: %d/%d", current_page + 1, max_pages);
    3239                 :          0 :                         mvprintw(g_max_row - 1, 1, "%s", current_page_str);
    3240                 :            : 
    3241                 :          0 :                         refresh();
    3242                 :            :                 }
    3243                 :            : 
    3244                 :          0 :                 c = getch();
    3245         [ #  # ]:          0 :                 if (c == 'q') {
    3246         [ #  # ]:          0 :                         pthread_mutex_lock(&g_thread_lock);
    3247                 :          0 :                         g_quit_app = true;
    3248         [ #  # ]:          0 :                         pthread_mutex_unlock(&g_thread_lock);
    3249                 :          0 :                         break;
    3250                 :            :                 }
    3251                 :            : 
    3252                 :          0 :                 force_refresh = true;
    3253                 :            : 
    3254   [ #  #  #  #  :          0 :                 switch (c) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    3255                 :          0 :                 case '1':
    3256                 :            :                 case '2':
    3257                 :            :                 case '3':
    3258                 :          0 :                         active_tab = c - '1';
    3259                 :          0 :                         current_page = 0;
    3260                 :          0 :                         g_selected_row = 0;
    3261                 :          0 :                         switch_tab(active_tab);
    3262                 :          0 :                         break;
    3263                 :          0 :                 case '\t':
    3264         [ #  # ]:          0 :                         if (active_tab < NUMBER_OF_TABS - 1) {
    3265                 :          0 :                                 active_tab++;
    3266                 :            :                         } else {
    3267                 :          0 :                                 active_tab = THREADS_TAB;
    3268                 :            :                         }
    3269                 :          0 :                         g_selected_row = 0;
    3270                 :          0 :                         current_page = 0;
    3271                 :          0 :                         switch_tab(active_tab);
    3272                 :          0 :                         break;
    3273                 :          0 :                 case 's':
    3274                 :          0 :                         sort_type2(active_tab, COL_THREADS_NONE);
    3275                 :          0 :                         change_sorting(active_tab, 0, NULL);
    3276                 :          0 :                         break;
    3277                 :          0 :                 case 'c':
    3278                 :          0 :                         filter_columns(active_tab);
    3279                 :          0 :                         break;
    3280                 :          0 :                 case 'r':
    3281                 :          0 :                         change_refresh_rate();
    3282                 :          0 :                         break;
    3283                 :          0 :                 case 't':
    3284         [ #  # ]:          0 :                         g_interval_data = !g_interval_data;
    3285                 :          0 :                         break;
    3286                 :          0 :                 case 'g':
    3287                 :          0 :                         show_scheduler(active_tab, current_page);
    3288                 :          0 :                         break;
    3289                 :          0 :                 case KEY_NPAGE: /* PgDown */
    3290         [ #  # ]:          0 :                         if (current_page + 1 < max_pages) {
    3291                 :          0 :                                 current_page++;
    3292                 :            :                         }
    3293                 :          0 :                         wclear(g_tabs[active_tab]);
    3294                 :          0 :                         g_selected_row = 0;
    3295                 :          0 :                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    3296                 :          0 :                         break;
    3297                 :          0 :                 case KEY_PPAGE: /* PgUp */
    3298         [ #  # ]:          0 :                         if (current_page > 0) {
    3299                 :          0 :                                 current_page--;
    3300                 :            :                         }
    3301                 :          0 :                         wclear(g_tabs[active_tab]);
    3302                 :          0 :                         g_selected_row = 0;
    3303                 :          0 :                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    3304                 :          0 :                         break;
    3305                 :          0 :                 case KEY_UP: /* Arrow up */
    3306         [ #  # ]:          0 :                         if (g_selected_row > 0) {
    3307                 :          0 :                                 g_selected_row--;
    3308         [ #  # ]:          0 :                         } else if (g_selected_row == 0) {
    3309         [ #  # ]:          0 :                                 if (current_page > 0) {
    3310                 :          0 :                                         current_page--;
    3311                 :          0 :                                         g_selected_row = g_max_data_rows - 1;
    3312                 :          0 :                                         wclear(g_tabs[active_tab]);
    3313                 :          0 :                                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    3314                 :            :                                 }
    3315                 :            :                         }
    3316                 :          0 :                         break;
    3317                 :          0 :                 case KEY_DOWN: /* Arrow down */
    3318         [ #  # ]:          0 :                         if (g_selected_row < g_max_selected_row) {
    3319                 :          0 :                                 g_selected_row++;
    3320         [ #  # ]:          0 :                         } else if (g_selected_row == g_max_selected_row) {
    3321         [ #  # ]:          0 :                                 if (current_page + 1 < max_pages) {
    3322                 :          0 :                                         current_page++;
    3323                 :          0 :                                         g_selected_row = 0;
    3324                 :          0 :                                         wclear(g_tabs[active_tab]);
    3325                 :          0 :                                         draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
    3326                 :            :                                 }
    3327                 :            :                         }
    3328                 :          0 :                         break;
    3329                 :          0 :                 case 10: /* Enter */
    3330         [ #  # ]:          0 :                         if (active_tab == THREADS_TAB) {
    3331                 :          0 :                                 show_thread(current_page, active_tab);
    3332         [ #  # ]:          0 :                         } else if (active_tab == CORES_TAB) {
    3333                 :          0 :                                 show_core(current_page, active_tab);
    3334         [ #  # ]:          0 :                         } else if (active_tab == POLLERS_TAB) {
    3335                 :          0 :                                 show_poller(current_page, active_tab);
    3336                 :            :                         }
    3337         [ #  # ]:          0 :                         snprintf(current_page_str, CURRENT_PAGE_STR_LEN - 1, "Page: %d/%d", current_page + 1, max_pages);
    3338                 :          0 :                         mvprintw(g_max_row - 1, 1, "%s", current_page_str);
    3339                 :          0 :                         refresh_after_popup(active_tab, &max_pages, current_page);
    3340                 :          0 :                         break;
    3341                 :          0 :                 case 'h':
    3342                 :          0 :                         help_window_display();
    3343                 :          0 :                         refresh_after_popup(active_tab, &max_pages, current_page);
    3344                 :          0 :                         break;
    3345                 :          0 :                 default:
    3346                 :          0 :                         force_refresh = false;
    3347                 :          0 :                         break;
    3348                 :            :                 }
    3349                 :            :         }
    3350                 :            : 
    3351                 :          0 :         pthread_join(*data_thread, NULL);
    3352                 :            : 
    3353                 :          0 :         free_poller_history();
    3354                 :            : 
    3355                 :            :         /* Free memory holding current data states before quitting application */
    3356         [ #  # ]:          0 :         for (i = 0; i < g_last_pollers_count; i++) {
    3357                 :          0 :                 free_rpc_poller(&g_pollers_info[i]);
    3358                 :            :         }
    3359         [ #  # ]:          0 :         for (i = 0; i < g_last_threads_count; i++) {
    3360                 :          0 :                 free_rpc_threads_stats(&g_threads_info[i]);
    3361                 :            :         }
    3362                 :          0 :         free_rpc_core_info(g_cores_info, g_last_cores_count);
    3363                 :          0 :         free_rpc_scheduler(&g_scheduler_info);
    3364                 :          0 : }
    3365                 :            : 
    3366                 :            : static void
    3367                 :          0 : draw_interface(void)
    3368                 :            : {
    3369                 :            :         int i;
    3370                 :          0 :         uint16_t required_size =  WINDOW_HEADER + 1;
    3371                 :            : 
    3372   [ #  #  #  # ]:          0 :         getmaxyx(stdscr, g_max_row, g_max_col);
    3373                 :          0 :         g_max_row = spdk_max(g_max_row, required_size);
    3374                 :          0 :         g_data_win_size = g_max_row - required_size;
    3375                 :          0 :         g_max_data_rows = g_max_row - WINDOW_HEADER;
    3376                 :            : 
    3377                 :          0 :         g_menu_win = newwin(MENU_WIN_HEIGHT, g_max_col, g_max_row - MENU_WIN_HEIGHT - 1,
    3378                 :            :                             MENU_WIN_LOCATION_COL);
    3379         [ #  # ]:          0 :         assert(g_menu_win != NULL);
    3380                 :          0 :         draw_menu_win();
    3381                 :            : 
    3382         [ #  # ]:          0 :         for (i = 0; i < NUMBER_OF_TABS; i++) {
    3383                 :          0 :                 g_tab_win[i] = newwin(TAB_WIN_HEIGHT, g_max_col / NUMBER_OF_TABS - TABS_SPACING,
    3384                 :          0 :                                       TAB_WIN_LOCATION_ROW, g_max_col / NUMBER_OF_TABS * i + 1);
    3385         [ #  # ]:          0 :                 assert(g_tab_win[i] != NULL);
    3386                 :          0 :                 draw_tab_win(i);
    3387                 :            : 
    3388                 :          0 :                 g_tabs[i] = newwin(g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 2, g_max_col, TABS_LOCATION_ROW,
    3389                 :            :                                    TABS_LOCATION_COL);
    3390                 :          0 :                 draw_tabs(i, g_current_sort_col[i], g_current_sort_col2[i]);
    3391                 :          0 :                 g_panels[i] = new_panel(g_tabs[i]);
    3392         [ #  # ]:          0 :                 assert(g_panels[i] != NULL);
    3393                 :            :         }
    3394                 :            : 
    3395                 :          0 :         update_panels();
    3396                 :          0 :         doupdate();
    3397                 :          0 : }
    3398                 :            : 
    3399                 :            : static void
    3400                 :          0 : finish(int sig)
    3401                 :            : {
    3402                 :            :         /* End ncurses mode */
    3403                 :          0 :         endwin();
    3404                 :          0 :         spdk_jsonrpc_client_close(g_rpc_client);
    3405                 :          0 :         exit(0);
    3406                 :            : }
    3407                 :            : 
    3408                 :            : static void
    3409                 :          0 : setup_ncurses(void)
    3410                 :            : {
    3411                 :          0 :         clear();
    3412                 :          0 :         noecho();
    3413                 :          0 :         timeout(1);
    3414                 :          0 :         curs_set(0);
    3415                 :          0 :         keypad(stdscr, TRUE);
    3416                 :          0 :         start_color();
    3417                 :          0 :         init_pair(1, COLOR_BLACK, COLOR_GREEN);
    3418                 :          0 :         init_pair(2, COLOR_BLACK, COLOR_WHITE);
    3419                 :          0 :         init_pair(3, COLOR_YELLOW, COLOR_BLACK);
    3420                 :          0 :         init_pair(4, COLOR_BLACK, COLOR_YELLOW);
    3421                 :          0 :         init_pair(5, COLOR_GREEN, COLOR_BLACK);
    3422                 :          0 :         init_pair(6, COLOR_RED, COLOR_BLACK);
    3423                 :          0 :         init_pair(7, COLOR_BLUE, COLOR_BLACK);
    3424                 :          0 :         init_pair(8, COLOR_RED, COLOR_WHITE);
    3425                 :          0 :         init_pair(9, COLOR_BLUE, COLOR_WHITE);
    3426                 :          0 :         init_pair(10, COLOR_WHITE, COLOR_BLACK);
    3427                 :            : 
    3428         [ #  # ]:          0 :         if (has_colors() == FALSE) {
    3429                 :          0 :                 endwin();
    3430         [ #  # ]:          0 :                 printf("Your terminal does not support color\n");
    3431                 :          0 :                 exit(1);
    3432                 :            :         }
    3433                 :            : 
    3434                 :            :         /* Handle signals to exit gracefully cleaning up ncurses */
    3435                 :          0 :         (void) signal(SIGINT, finish);
    3436                 :          0 :         (void) signal(SIGPIPE, finish);
    3437                 :          0 :         (void) signal(SIGABRT, finish);
    3438                 :          0 : }
    3439                 :            : 
    3440                 :            : static void
    3441                 :          0 : usage(const char *program_name)
    3442                 :            : {
    3443         [ #  # ]:          0 :         printf("%s [options]", program_name);
    3444                 :          0 :         printf("\n");
    3445         [ #  # ]:          0 :         printf("options:\n");
    3446         [ #  # ]:          0 :         printf(" -r <path>  RPC connect address (default: /var/tmp/spdk.sock)\n");
    3447         [ #  # ]:          0 :         printf(" -h         show this usage\n");
    3448                 :          0 : }
    3449                 :            : 
    3450                 :            : static int
    3451                 :          0 : rpc_decode_tick_rate(struct spdk_json_val *val, uint64_t *tick_rate)
    3452                 :            : {
    3453                 :            :         struct t_rate {
    3454                 :            :                 uint64_t tr;
    3455                 :            :         };
    3456                 :            : 
    3457                 :          0 :         const struct spdk_json_object_decoder rpc_tick_rate_decoder[] = {
    3458                 :            :                 {"tick_rate", offsetof(struct t_rate, tr), spdk_json_decode_uint64}
    3459                 :            :         };
    3460                 :            : 
    3461                 :            :         int rc;
    3462                 :          0 :         struct t_rate tmp;
    3463                 :            : 
    3464                 :          0 :         rc = spdk_json_decode_object_relaxed(val, rpc_tick_rate_decoder,
    3465                 :            :                                              SPDK_COUNTOF(rpc_tick_rate_decoder), &tmp);
    3466                 :            : 
    3467                 :          0 :         *tick_rate = tmp.tr;
    3468                 :            : 
    3469                 :          0 :         return rc;
    3470                 :            : }
    3471                 :            : 
    3472                 :            : static int
    3473                 :          0 : wait_init(pthread_t *data_thread)
    3474                 :            : {
    3475                 :          0 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
    3476                 :          0 :         char *uninit_log = "Waiting for SPDK target application to initialize...",
    3477                 :          0 :               *uninit_error = "Unable to read SPDK application state!";
    3478                 :          0 :         int c, max_col, rc = 0;
    3479                 :          0 :         uint64_t tick_rate;
    3480                 :            : 
    3481         [ #  # ]:          0 :         max_col = getmaxx(stdscr);
    3482                 :          0 :         print_in_middle(stdscr, FIRST_DATA_ROW, 1, max_col, uninit_log, COLOR_PAIR(5));
    3483                 :          0 :         rc = rpc_send_req("framework_wait_init", &json_resp);
    3484         [ #  # ]:          0 :         if (rc) {
    3485                 :            :                 while (1) {
    3486                 :          0 :                         print_in_middle(stdscr, FIRST_DATA_ROW, 1, max_col, uninit_error, COLOR_PAIR(8));
    3487                 :          0 :                         c = getch();
    3488         [ #  # ]:          0 :                         if (c == 'q') {
    3489                 :          0 :                                 return -1;
    3490                 :            :                         }
    3491                 :            :                 }
    3492                 :            :         }
    3493                 :            : 
    3494                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
    3495                 :            : 
    3496                 :          0 :         rc = pthread_mutex_init(&g_thread_lock, NULL);
    3497         [ #  # ]:          0 :         if (rc) {
    3498         [ #  # ]:          0 :                 fprintf(stderr, "mutex lock failed to initialize: %d\n", errno);
    3499                 :          0 :                 return -1;
    3500                 :            :         }
    3501                 :            : 
    3502                 :          0 :         memset(&g_threads_info, 0, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
    3503                 :          0 :         memset(&g_cores_info, 0, sizeof(struct rpc_core_info) * RPC_MAX_CORES);
    3504                 :            : 
    3505                 :            :         /* Decode tick rate */
    3506                 :          0 :         rc = rpc_send_req("framework_get_reactors", &json_resp);
    3507         [ #  # ]:          0 :         if (rc) {
    3508                 :          0 :                 return rc;
    3509                 :            :         }
    3510                 :            : 
    3511         [ #  # ]:          0 :         if (rpc_decode_tick_rate(json_resp->result, &tick_rate)) {
    3512                 :          0 :                 spdk_jsonrpc_client_free_response(json_resp);
    3513                 :          0 :                 return -EINVAL;
    3514                 :            :         }
    3515                 :            : 
    3516                 :          0 :         spdk_jsonrpc_client_free_response(json_resp);
    3517                 :            : 
    3518                 :          0 :         g_tick_rate = tick_rate;
    3519                 :            : 
    3520                 :            :         /* This is to get first batch of data for display functions.
    3521                 :            :          * Since data thread makes RPC calls that take more time than
    3522                 :            :          * startup of display functions on main thread, without these
    3523                 :            :          * calls both threads would be subject to a race condition. */
    3524                 :          0 :         rc = get_thread_data();
    3525         [ #  # ]:          0 :         if (rc) {
    3526                 :          0 :                 return -1;
    3527                 :            :         }
    3528                 :            : 
    3529                 :          0 :         rc = get_pollers_data();
    3530         [ #  # ]:          0 :         if (rc) {
    3531                 :          0 :                 return -1;
    3532                 :            :         }
    3533                 :            : 
    3534                 :          0 :         rc = get_cores_data();
    3535         [ #  # ]:          0 :         if (rc) {
    3536                 :          0 :                 return -1;
    3537                 :            :         }
    3538                 :            : 
    3539         [ #  # ]:          0 :         rc = pthread_create(data_thread, NULL, &data_thread_routine, NULL);
    3540         [ #  # ]:          0 :         if (rc) {
    3541         [ #  # ]:          0 :                 fprintf(stderr, "data thread creation failed: %d\n", errno);
    3542                 :          0 :                 return -1;
    3543                 :            :         }
    3544                 :          0 :         return 0;
    3545                 :            : }
    3546                 :            : 
    3547                 :            : int
    3548                 :          0 : main(int argc, char **argv)
    3549                 :            : {
    3550                 :            :         int op, rc;
    3551                 :          0 :         char *socket = SPDK_DEFAULT_RPC_ADDR;
    3552                 :          0 :         pthread_t data_thread;
    3553                 :            : 
    3554   [ #  #  #  # ]:          0 :         while ((op = getopt(argc, argv, "r:h")) != -1) {
    3555         [ #  # ]:          0 :                 switch (op) {
    3556                 :          0 :                 case 'r':
    3557                 :          0 :                         socket = optarg;
    3558                 :          0 :                         break;
    3559                 :          0 :                 default:
    3560                 :          0 :                         usage(argv[0]);
    3561                 :          0 :                         return op == 'h' ? 0 : 1;
    3562                 :            :                 }
    3563                 :            :         }
    3564                 :            : 
    3565         [ #  # ]:          0 :         g_rpc_client = spdk_jsonrpc_client_connect(socket, socket[0] == '/' ? AF_UNIX : AF_INET);
    3566         [ #  # ]:          0 :         if (!g_rpc_client) {
    3567         [ #  # ]:          0 :                 fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
    3568                 :          0 :                 return 1;
    3569                 :            :         }
    3570                 :            : 
    3571                 :          0 :         initscr();
    3572                 :          0 :         init_str_len();
    3573                 :          0 :         setup_ncurses();
    3574                 :          0 :         draw_interface();
    3575                 :            : 
    3576                 :          0 :         rc = wait_init(&data_thread);
    3577         [ #  # ]:          0 :         if (!rc) {
    3578                 :          0 :                 show_stats(&data_thread);
    3579                 :            :         }
    3580                 :            : 
    3581                 :          0 :         finish(0);
    3582                 :            : 
    3583                 :          0 :         return (0);
    3584                 :            : }

Generated by: LCOV version 1.14