2022-06-03 19:15:11 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
2022-11-01 20:26:26 +00:00
|
|
|
* Copyright (C) 2020 Intel Corporation.
|
2020-04-14 07:01:41 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk/jsonrpc.h"
|
|
|
|
#include "spdk/rpc.h"
|
|
|
|
#include "spdk/event.h"
|
|
|
|
#include "spdk/util.h"
|
2020-02-28 13:00:08 +00:00
|
|
|
#include "spdk/env.h"
|
|
|
|
|
2020-05-27 18:32:44 +00:00
|
|
|
#if defined __has_include
|
|
|
|
#if __has_include(<ncurses/panel.h>)
|
|
|
|
#include <ncurses/ncurses.h>
|
|
|
|
#include <ncurses/panel.h>
|
|
|
|
#include <ncurses/menu.h>
|
|
|
|
#else
|
2020-02-28 13:00:08 +00:00
|
|
|
#include <ncurses.h>
|
|
|
|
#include <panel.h>
|
2020-03-27 09:13:14 +00:00
|
|
|
#include <menu.h>
|
2020-05-27 18:32:44 +00:00
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#include <ncurses.h>
|
|
|
|
#include <panel.h>
|
|
|
|
#include <menu.h>
|
|
|
|
#endif
|
2020-04-14 07:01:41 +00:00
|
|
|
|
|
|
|
#define RPC_MAX_THREADS 1024
|
|
|
|
#define RPC_MAX_POLLERS 1024
|
2020-03-09 12:14:43 +00:00
|
|
|
#define RPC_MAX_CORES 255
|
2020-03-27 09:13:14 +00:00
|
|
|
#define MAX_THREAD_NAME 128
|
|
|
|
#define MAX_POLLER_NAME 128
|
2020-04-20 11:50:14 +00:00
|
|
|
#define MAX_THREADS 4096
|
2020-04-10 05:32:35 +00:00
|
|
|
#define RR_MAX_VALUE 255
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
#define MAX_STRING_LEN 12289 /* 3x 4k monitors + 1 */
|
|
|
|
#define TAB_WIN_HEIGHT 3
|
|
|
|
#define TAB_WIN_LOCATION_ROW 1
|
|
|
|
#define TABS_SPACING 2
|
|
|
|
#define TABS_LOCATION_ROW 4
|
|
|
|
#define TABS_LOCATION_COL 0
|
|
|
|
#define TABS_DATA_START_ROW 3
|
2020-03-05 07:57:27 +00:00
|
|
|
#define TABS_DATA_START_COL 2
|
2020-03-27 09:13:14 +00:00
|
|
|
#define TABS_COL_COUNT 10
|
2020-02-28 13:00:08 +00:00
|
|
|
#define MENU_WIN_HEIGHT 3
|
|
|
|
#define MENU_WIN_SPACING 4
|
|
|
|
#define MENU_WIN_LOCATION_COL 0
|
2020-04-10 05:32:35 +00:00
|
|
|
#define RR_WIN_WIDTH 32
|
|
|
|
#define RR_WIN_HEIGHT 5
|
2020-03-05 07:57:27 +00:00
|
|
|
#define MAX_THREAD_NAME_LEN 26
|
2020-03-09 12:14:43 +00:00
|
|
|
#define MAX_THREAD_COUNT_STR_LEN 14
|
2020-03-05 07:57:27 +00:00
|
|
|
#define MAX_POLLER_NAME_LEN 36
|
|
|
|
#define MAX_POLLER_COUNT_STR_LEN 16
|
|
|
|
#define MAX_POLLER_TYPE_STR_LEN 8
|
2021-06-17 10:01:39 +00:00
|
|
|
#define MAX_STATUS_IND_STR_LEN 8
|
2021-07-22 11:29:16 +00:00
|
|
|
#define MAX_POLLER_IND_STR_LEN 28
|
2020-03-09 12:14:43 +00:00
|
|
|
#define MAX_CORE_MASK_STR_LEN 16
|
|
|
|
#define MAX_CORE_STR_LEN 6
|
2021-02-26 09:36:57 +00:00
|
|
|
#define MAX_CORE_FREQ_STR_LEN 18
|
2020-12-09 09:42:49 +00:00
|
|
|
#define MAX_TIME_STR_LEN 12
|
2020-12-16 23:53:50 +00:00
|
|
|
#define MAX_CPU_STR_LEN 8
|
2020-12-09 09:42:49 +00:00
|
|
|
#define MAX_POLLER_RUN_COUNT 20
|
2020-04-16 13:34:15 +00:00
|
|
|
#define MAX_PERIOD_STR_LEN 12
|
2021-05-14 09:18:26 +00:00
|
|
|
#define MAX_INTR_LEN 6
|
2020-03-09 12:14:43 +00:00
|
|
|
#define WINDOW_HEADER 12
|
2020-04-20 11:50:14 +00:00
|
|
|
#define FROM_HEX 16
|
2020-04-07 13:08:09 +00:00
|
|
|
#define THREAD_WIN_WIDTH 69
|
2021-09-01 10:07:26 +00:00
|
|
|
#define THREAD_WIN_HEIGHT 9
|
2020-04-07 13:08:09 +00:00
|
|
|
#define THREAD_WIN_FIRST_COL 2
|
2020-11-30 13:10:46 +00:00
|
|
|
#define CORE_WIN_FIRST_COL 16
|
2020-12-09 09:42:49 +00:00
|
|
|
#define CORE_WIN_WIDTH 48
|
2021-03-04 11:54:25 +00:00
|
|
|
#define CORE_WIN_HEIGHT 11
|
2020-12-08 09:46:41 +00:00
|
|
|
#define POLLER_WIN_HEIGHT 8
|
2020-12-09 09:42:49 +00:00
|
|
|
#define POLLER_WIN_WIDTH 64
|
2020-11-30 13:38:00 +00:00
|
|
|
#define POLLER_WIN_FIRST_COL 14
|
2021-03-29 12:39:46 +00:00
|
|
|
#define FIRST_DATA_ROW 7
|
2021-01-26 10:30:37 +00:00
|
|
|
#define HELP_WIN_WIDTH 88
|
2022-04-11 10:24:13 +00:00
|
|
|
#define HELP_WIN_HEIGHT 24
|
|
|
|
#define SCHEDULER_WIN_HEIGHT 7
|
|
|
|
#define SCHEDULER_WIN_FIRST_COL 2
|
|
|
|
#define MAX_SCHEDULER_PERIOD_STR_LEN 10
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
enum tabs {
|
|
|
|
THREADS_TAB,
|
|
|
|
POLLERS_TAB,
|
|
|
|
CORES_TAB,
|
|
|
|
NUMBER_OF_TABS,
|
|
|
|
};
|
|
|
|
|
2021-11-03 17:22:59 +00:00
|
|
|
enum column_threads_type {
|
|
|
|
COL_THREADS_NAME,
|
|
|
|
COL_THREADS_CORE,
|
|
|
|
COL_THREADS_ACTIVE_POLLERS,
|
|
|
|
COL_THREADS_TIMED_POLLERS,
|
|
|
|
COL_THREADS_PAUSED_POLLERS,
|
|
|
|
COL_THREADS_IDLE_TIME,
|
|
|
|
COL_THREADS_BUSY_TIME,
|
2020-12-16 23:53:50 +00:00
|
|
|
COL_THREADS_CPU_USAGE,
|
2021-06-17 10:01:39 +00:00
|
|
|
COL_THREADS_STATUS,
|
2021-10-13 16:03:59 +00:00
|
|
|
COL_THREADS_NONE = 255,
|
2021-11-03 17:22:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum column_pollers_type {
|
|
|
|
COL_POLLERS_NAME,
|
|
|
|
COL_POLLERS_TYPE,
|
|
|
|
COL_POLLERS_THREAD_NAME,
|
|
|
|
COL_POLLERS_RUN_COUNTER,
|
|
|
|
COL_POLLERS_PERIOD,
|
|
|
|
COL_POLLERS_BUSY_COUNT,
|
2021-10-13 16:03:59 +00:00
|
|
|
COL_POLLERS_NONE = 255,
|
2021-11-03 17:22:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum column_cores_type {
|
|
|
|
COL_CORES_CORE,
|
|
|
|
COL_CORES_THREADS,
|
|
|
|
COL_CORES_POLLERS,
|
|
|
|
COL_CORES_IDLE_TIME,
|
|
|
|
COL_CORES_BUSY_TIME,
|
|
|
|
COL_CORES_CORE_FREQ,
|
|
|
|
COL_CORES_INTR,
|
2020-12-16 23:53:50 +00:00
|
|
|
COL_CORES_CPU_USAGE,
|
2021-06-17 10:01:39 +00:00
|
|
|
COL_CORES_STATUS,
|
2021-10-13 16:03:59 +00:00
|
|
|
COL_CORES_NONE = 255,
|
2021-11-03 17:22:59 +00:00
|
|
|
};
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
enum spdk_poller_type {
|
|
|
|
SPDK_ACTIVE_POLLER,
|
|
|
|
SPDK_TIMED_POLLER,
|
|
|
|
SPDK_PAUSED_POLLER,
|
|
|
|
SPDK_POLLER_TYPES_COUNT,
|
|
|
|
};
|
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
struct col_desc {
|
|
|
|
const char *name;
|
|
|
|
uint8_t name_len;
|
2020-03-05 07:57:27 +00:00
|
|
|
uint8_t max_data_string;
|
2020-04-20 09:14:19 +00:00
|
|
|
bool disabled;
|
|
|
|
};
|
|
|
|
|
2020-04-09 08:32:00 +00:00
|
|
|
struct run_counter_history {
|
2021-08-05 14:29:55 +00:00
|
|
|
uint64_t poller_id;
|
2020-04-09 08:32:00 +00:00
|
|
|
uint64_t thread_id;
|
|
|
|
uint64_t last_run_counter;
|
2021-07-13 09:33:33 +00:00
|
|
|
uint64_t last_busy_counter;
|
2020-04-09 08:32:00 +00:00
|
|
|
TAILQ_ENTRY(run_counter_history) link;
|
|
|
|
};
|
|
|
|
|
2020-04-10 05:32:35 +00:00
|
|
|
uint8_t g_sleep_time = 1;
|
2020-04-07 10:44:59 +00:00
|
|
|
uint16_t g_selected_row;
|
|
|
|
uint16_t g_max_selected_row;
|
2021-06-28 11:27:00 +00:00
|
|
|
uint64_t g_tick_rate;
|
2020-03-27 09:13:14 +00:00
|
|
|
const char *poller_type_str[SPDK_POLLER_TYPES_COUNT] = {"Active", "Timed", "Paused"};
|
2020-02-28 13:00:08 +00:00
|
|
|
const char *g_tab_title[NUMBER_OF_TABS] = {"[1] THREADS", "[2] POLLERS", "[3] CORES"};
|
2020-04-14 07:01:41 +00:00
|
|
|
struct spdk_jsonrpc_client *g_rpc_client;
|
2020-04-09 08:32:00 +00:00
|
|
|
static TAILQ_HEAD(, run_counter_history) g_run_counter_history = TAILQ_HEAD_INITIALIZER(
|
|
|
|
g_run_counter_history);
|
2020-02-28 13:00:08 +00:00
|
|
|
WINDOW *g_menu_win, *g_tab_win[NUMBER_OF_TABS], *g_tabs[NUMBER_OF_TABS];
|
2020-03-27 09:13:14 +00:00
|
|
|
PANEL *g_panels[NUMBER_OF_TABS];
|
2020-02-28 13:00:08 +00:00
|
|
|
uint16_t g_max_row, g_max_col;
|
2020-03-09 12:14:43 +00:00
|
|
|
uint16_t g_data_win_size, g_max_data_rows;
|
2020-02-28 13:00:08 +00:00
|
|
|
uint32_t g_last_threads_count, g_last_pollers_count, g_last_cores_count;
|
2021-11-03 17:22:59 +00:00
|
|
|
uint8_t g_current_sort_col[NUMBER_OF_TABS] = {COL_THREADS_NAME, COL_POLLERS_NAME, COL_CORES_CORE};
|
2021-10-13 16:03:59 +00:00
|
|
|
uint8_t g_current_sort_col2[NUMBER_OF_TABS] = {COL_THREADS_NONE, COL_POLLERS_NONE, COL_CORES_NONE};
|
2020-12-09 09:42:49 +00:00
|
|
|
bool g_interval_data = true;
|
2021-02-02 09:27:16 +00:00
|
|
|
bool g_quit_app = false;
|
|
|
|
pthread_mutex_t g_thread_lock;
|
2020-04-20 09:14:19 +00:00
|
|
|
static struct col_desc g_col_desc[NUMBER_OF_TABS][TABS_COL_COUNT] = {
|
2020-03-05 07:57:27 +00:00
|
|
|
{ {.name = "Thread name", .max_data_string = MAX_THREAD_NAME_LEN},
|
2020-04-20 11:50:14 +00:00
|
|
|
{.name = "Core", .max_data_string = MAX_CORE_STR_LEN},
|
2020-03-05 07:57:27 +00:00
|
|
|
{.name = "Active pollers", .max_data_string = MAX_POLLER_COUNT_STR_LEN},
|
|
|
|
{.name = "Timed pollers", .max_data_string = MAX_POLLER_COUNT_STR_LEN},
|
|
|
|
{.name = "Paused pollers", .max_data_string = MAX_POLLER_COUNT_STR_LEN},
|
2020-04-16 13:34:15 +00:00
|
|
|
{.name = "Idle [us]", .max_data_string = MAX_TIME_STR_LEN},
|
|
|
|
{.name = "Busy [us]", .max_data_string = MAX_TIME_STR_LEN},
|
2020-12-16 23:53:50 +00:00
|
|
|
{.name = "CPU %", .max_data_string = MAX_CPU_STR_LEN},
|
2021-06-17 10:01:39 +00:00
|
|
|
{.name = "Status", .max_data_string = MAX_STATUS_IND_STR_LEN},
|
2020-04-20 09:14:19 +00:00
|
|
|
{.name = (char *)NULL}
|
2020-03-27 09:13:14 +00:00
|
|
|
},
|
2020-03-05 07:57:27 +00:00
|
|
|
{ {.name = "Poller name", .max_data_string = MAX_POLLER_NAME_LEN},
|
|
|
|
{.name = "Type", .max_data_string = MAX_POLLER_TYPE_STR_LEN},
|
|
|
|
{.name = "On thread", .max_data_string = MAX_THREAD_NAME_LEN},
|
2020-12-09 09:42:49 +00:00
|
|
|
{.name = "Run count", .max_data_string = MAX_POLLER_RUN_COUNT},
|
2020-04-16 13:34:15 +00:00
|
|
|
{.name = "Period [us]", .max_data_string = MAX_PERIOD_STR_LEN},
|
2021-07-22 11:29:16 +00:00
|
|
|
{.name = "Status (busy count)", .max_data_string = MAX_POLLER_IND_STR_LEN},
|
2020-04-20 09:14:19 +00:00
|
|
|
{.name = (char *)NULL}
|
2020-03-27 09:13:14 +00:00
|
|
|
},
|
2020-04-20 09:30:15 +00:00
|
|
|
{ {.name = "Core", .max_data_string = MAX_CORE_STR_LEN},
|
2020-03-09 12:14:43 +00:00
|
|
|
{.name = "Thread count", .max_data_string = MAX_THREAD_COUNT_STR_LEN},
|
|
|
|
{.name = "Poller count", .max_data_string = MAX_POLLER_COUNT_STR_LEN},
|
2020-04-16 13:34:15 +00:00
|
|
|
{.name = "Idle [us]", .max_data_string = MAX_TIME_STR_LEN},
|
|
|
|
{.name = "Busy [us]", .max_data_string = MAX_TIME_STR_LEN},
|
2021-02-26 09:36:57 +00:00
|
|
|
{.name = "Frequency [MHz]", .max_data_string = MAX_CORE_FREQ_STR_LEN},
|
2021-05-14 09:18:26 +00:00
|
|
|
{.name = "Intr", .max_data_string = MAX_INTR_LEN},
|
2020-12-16 23:53:50 +00:00
|
|
|
{.name = "CPU %", .max_data_string = MAX_CPU_STR_LEN},
|
2021-06-17 10:01:39 +00:00
|
|
|
{.name = "Status", .max_data_string = MAX_STATUS_IND_STR_LEN},
|
2020-04-20 09:14:19 +00:00
|
|
|
{.name = (char *)NULL}
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
};
|
2020-04-14 07:01:41 +00:00
|
|
|
|
|
|
|
struct rpc_thread_info {
|
|
|
|
char *name;
|
|
|
|
uint64_t id;
|
2021-05-28 12:39:55 +00:00
|
|
|
int core_num;
|
2020-04-14 07:01:41 +00:00
|
|
|
char *cpumask;
|
|
|
|
uint64_t busy;
|
2020-04-09 08:32:00 +00:00
|
|
|
uint64_t last_busy;
|
2020-04-14 07:01:41 +00:00
|
|
|
uint64_t idle;
|
2020-04-09 08:32:00 +00:00
|
|
|
uint64_t last_idle;
|
2020-04-14 07:01:41 +00:00
|
|
|
uint64_t active_pollers_count;
|
|
|
|
uint64_t timed_pollers_count;
|
|
|
|
uint64_t paused_pollers_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rpc_poller_info {
|
|
|
|
char *name;
|
|
|
|
char *state;
|
2021-08-05 14:29:55 +00:00
|
|
|
uint64_t id;
|
2020-04-14 07:01:41 +00:00
|
|
|
uint64_t run_count;
|
|
|
|
uint64_t busy_count;
|
|
|
|
uint64_t period_ticks;
|
2020-03-27 09:13:14 +00:00
|
|
|
enum spdk_poller_type type;
|
|
|
|
char thread_name[MAX_THREAD_NAME];
|
2020-04-09 08:32:00 +00:00
|
|
|
uint64_t thread_id;
|
2020-04-14 07:01:41 +00:00
|
|
|
};
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
struct rpc_core_thread_info {
|
|
|
|
char *name;
|
|
|
|
uint64_t id;
|
|
|
|
char *cpumask;
|
|
|
|
uint64_t elapsed;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rpc_core_threads {
|
|
|
|
uint64_t threads_count;
|
2021-02-16 12:07:22 +00:00
|
|
|
struct rpc_core_thread_info *thread;
|
2020-03-09 12:14:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct rpc_core_info {
|
|
|
|
uint32_t lcore;
|
2021-02-16 12:07:22 +00:00
|
|
|
uint64_t pollers_count;
|
2020-03-09 12:14:43 +00:00
|
|
|
uint64_t busy;
|
|
|
|
uint64_t idle;
|
2021-02-26 09:36:57 +00:00
|
|
|
uint32_t core_freq;
|
2021-02-16 12:07:22 +00:00
|
|
|
uint64_t last_idle;
|
|
|
|
uint64_t last_busy;
|
2021-05-14 09:18:26 +00:00
|
|
|
bool in_interrupt;
|
2020-03-09 12:14:43 +00:00
|
|
|
struct rpc_core_threads threads;
|
|
|
|
};
|
|
|
|
|
2021-01-15 16:14:16 +00:00
|
|
|
struct rpc_scheduler {
|
|
|
|
char *scheduler_name;
|
2022-04-11 10:24:13 +00:00
|
|
|
char *governor_name;
|
2021-01-15 16:14:16 +00:00
|
|
|
uint64_t scheduler_period;
|
|
|
|
};
|
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
struct rpc_thread_info g_threads_info[RPC_MAX_THREADS];
|
2021-06-22 11:44:20 +00:00
|
|
|
struct rpc_poller_info g_pollers_info[RPC_MAX_POLLERS];
|
2021-06-28 11:27:00 +00:00
|
|
|
struct rpc_core_info g_cores_info[RPC_MAX_CORES];
|
2021-01-15 16:14:16 +00:00
|
|
|
struct rpc_scheduler g_scheduler_info;
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
static void
|
|
|
|
init_str_len(void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
for (j = 0; g_col_desc[i][j].name != NULL; j++) {
|
|
|
|
g_col_desc[i][j].name_len = strlen(g_col_desc[i][j].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
static void
|
2021-06-28 11:42:53 +00:00
|
|
|
free_rpc_threads_stats(struct rpc_thread_info *req)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
2021-06-28 11:42:53 +00:00
|
|
|
free(req->name);
|
|
|
|
req->name = NULL;
|
|
|
|
free(req->cpumask);
|
|
|
|
req->cpumask = NULL;
|
2020-04-14 07:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct spdk_json_object_decoder rpc_thread_info_decoders[] = {
|
|
|
|
{"name", offsetof(struct rpc_thread_info, name), spdk_json_decode_string},
|
|
|
|
{"id", offsetof(struct rpc_thread_info, id), spdk_json_decode_uint64},
|
|
|
|
{"cpumask", offsetof(struct rpc_thread_info, cpumask), spdk_json_decode_string},
|
|
|
|
{"busy", offsetof(struct rpc_thread_info, busy), spdk_json_decode_uint64},
|
|
|
|
{"idle", offsetof(struct rpc_thread_info, idle), spdk_json_decode_uint64},
|
|
|
|
{"active_pollers_count", offsetof(struct rpc_thread_info, active_pollers_count), spdk_json_decode_uint64},
|
|
|
|
{"timed_pollers_count", offsetof(struct rpc_thread_info, timed_pollers_count), spdk_json_decode_uint64},
|
|
|
|
{"paused_pollers_count", offsetof(struct rpc_thread_info, paused_pollers_count), spdk_json_decode_uint64},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2021-06-28 11:42:53 +00:00
|
|
|
rpc_decode_threads_array(struct spdk_json_val *val, struct rpc_thread_info *out,
|
|
|
|
uint64_t *current_threads_count)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
2021-06-28 11:42:53 +00:00
|
|
|
struct spdk_json_val *thread = val;
|
|
|
|
uint64_t i = 0;
|
|
|
|
int rc;
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
/* Fetch the beginning of threads array */
|
|
|
|
rc = spdk_json_find_array(thread, "threads", NULL, &thread);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not fetch threads array from JSON.\n");
|
|
|
|
goto end;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
for (thread = spdk_json_array_first(thread); thread != NULL; thread = spdk_json_next(thread)) {
|
|
|
|
rc = spdk_json_decode_object(thread, rpc_thread_info_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_thread_info_decoders), &out[i]);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not decode thread object from JSON.\n");
|
|
|
|
break;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
i++;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
end:
|
|
|
|
|
|
|
|
*current_threads_count = i;
|
|
|
|
return rc;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
free_rpc_poller(struct rpc_poller_info *poller)
|
|
|
|
{
|
|
|
|
free(poller->name);
|
|
|
|
poller->name = NULL;
|
|
|
|
free(poller->state);
|
|
|
|
poller->state = NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
static void
|
2021-06-28 11:27:00 +00:00
|
|
|
free_rpc_core_info(struct rpc_core_info *core_info, size_t size)
|
2020-03-09 12:14:43 +00:00
|
|
|
{
|
2021-06-28 11:27:00 +00:00
|
|
|
struct rpc_core_threads *threads;
|
2020-03-09 12:14:43 +00:00
|
|
|
struct rpc_core_thread_info *thread;
|
2021-06-28 11:27:00 +00:00
|
|
|
uint64_t i, core_number;
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
for (core_number = 0; core_number < size; core_number++) {
|
|
|
|
threads = &core_info[core_number].threads;
|
|
|
|
for (i = 0; i < threads->threads_count; i++) {
|
|
|
|
thread = &threads->thread[i];
|
2020-03-09 12:14:43 +00:00
|
|
|
free(thread->name);
|
|
|
|
free(thread->cpumask);
|
|
|
|
}
|
2021-06-28 11:27:00 +00:00
|
|
|
free(threads->thread);
|
2020-03-09 12:14:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
static const struct spdk_json_object_decoder rpc_pollers_decoders[] = {
|
|
|
|
{"name", offsetof(struct rpc_poller_info, name), spdk_json_decode_string},
|
|
|
|
{"state", offsetof(struct rpc_poller_info, state), spdk_json_decode_string},
|
2021-08-05 14:29:55 +00:00
|
|
|
{"id", offsetof(struct rpc_poller_info, id), spdk_json_decode_uint64},
|
2020-04-14 07:01:41 +00:00
|
|
|
{"run_count", offsetof(struct rpc_poller_info, run_count), spdk_json_decode_uint64},
|
|
|
|
{"busy_count", offsetof(struct rpc_poller_info, busy_count), spdk_json_decode_uint64},
|
|
|
|
{"period_ticks", offsetof(struct rpc_poller_info, period_ticks), spdk_json_decode_uint64, true},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2021-06-22 11:44:20 +00:00
|
|
|
rpc_decode_pollers_array(struct spdk_json_val *poller, struct rpc_poller_info *out,
|
|
|
|
uint64_t *poller_count,
|
|
|
|
const char *thread_name, uint64_t thread_name_length, uint64_t thread_id,
|
|
|
|
enum spdk_poller_type poller_type)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
2021-06-22 11:44:20 +00:00
|
|
|
int rc;
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
for (poller = spdk_json_array_first(poller); poller != NULL; poller = spdk_json_next(poller)) {
|
|
|
|
out[*poller_count].thread_id = thread_id;
|
|
|
|
memcpy(out[*poller_count].thread_name, thread_name, sizeof(char) * thread_name_length);
|
|
|
|
out[*poller_count].type = poller_type;
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
rc = spdk_json_decode_object(poller, rpc_pollers_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_pollers_decoders), &out[*poller_count]);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not decode poller object from JSON.\n");
|
|
|
|
return rc;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
(*poller_count)++;
|
|
|
|
if (*poller_count == RPC_MAX_POLLERS) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-04-14 07:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
static const struct spdk_json_object_decoder rpc_thread_pollers_decoders[] = {
|
|
|
|
{"name", offsetof(struct rpc_thread_info, name), spdk_json_decode_string},
|
|
|
|
{"id", offsetof(struct rpc_thread_info, id), spdk_json_decode_uint64},
|
2020-04-14 07:01:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2021-06-22 11:44:20 +00:00
|
|
|
rpc_decode_pollers_threads_array(struct spdk_json_val *val, struct rpc_poller_info *out,
|
|
|
|
uint32_t *num_pollers)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
2021-06-22 11:44:20 +00:00
|
|
|
struct spdk_json_val *thread = val, *poller;
|
|
|
|
/* This is a temporary poller structure to hold thread name and id.
|
|
|
|
* It is filled with data only once per thread change and then
|
|
|
|
* that memory is copied to each poller running on that thread. */
|
|
|
|
struct rpc_thread_info thread_info = {};
|
|
|
|
uint64_t poller_count = 0, i, thread_name_length;
|
|
|
|
int rc;
|
|
|
|
const char *poller_typenames[] = { "active_pollers", "timed_pollers", "paused_pollers" };
|
|
|
|
enum spdk_poller_type poller_types[] = { SPDK_ACTIVE_POLLER, SPDK_TIMED_POLLER, SPDK_PAUSED_POLLER };
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
/* Fetch the beginning of threads array */
|
|
|
|
rc = spdk_json_find_array(thread, "threads", NULL, &thread);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not fetch threads array from JSON.\n");
|
|
|
|
goto end;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
for (thread = spdk_json_array_first(thread); thread != NULL; thread = spdk_json_next(thread)) {
|
|
|
|
rc = spdk_json_decode_object_relaxed(thread, rpc_thread_pollers_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_thread_pollers_decoders), &thread_info);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not decode thread info from JSON.\n");
|
|
|
|
goto end;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
thread_name_length = strlen(thread_info.name);
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
for (i = 0; i < SPDK_COUNTOF(poller_types); i++) {
|
|
|
|
/* Find poller array */
|
|
|
|
rc = spdk_json_find(thread, poller_typenames[i], NULL, &poller,
|
|
|
|
SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not fetch pollers array from JSON.\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = rpc_decode_pollers_array(poller, out, &poller_count, thread_info.name,
|
|
|
|
thread_name_length,
|
|
|
|
thread_info.id, poller_types[i]);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not decode the first object in pollers array.\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*num_pollers = poller_count;
|
|
|
|
|
|
|
|
end:
|
|
|
|
/* Since we rely in spdk_json_object_decode() to free this value
|
|
|
|
* each time we rewrite it, we need to free the last allocation
|
|
|
|
* manually. */
|
|
|
|
free(thread_info.name);
|
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
*num_pollers = 0;
|
|
|
|
for (i = 0; i < poller_count; i++) {
|
|
|
|
free_rpc_poller(&out[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
static const struct spdk_json_object_decoder rpc_core_thread_info_decoders[] = {
|
|
|
|
{"name", offsetof(struct rpc_core_thread_info, name), spdk_json_decode_string},
|
|
|
|
{"id", offsetof(struct rpc_core_thread_info, id), spdk_json_decode_uint64},
|
|
|
|
{"cpumask", offsetof(struct rpc_core_thread_info, cpumask), spdk_json_decode_string},
|
|
|
|
{"elapsed", offsetof(struct rpc_core_thread_info, elapsed), spdk_json_decode_uint64},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
rpc_decode_core_threads_object(const struct spdk_json_val *val, void *out)
|
|
|
|
{
|
|
|
|
struct rpc_core_thread_info *info = out;
|
|
|
|
|
|
|
|
return spdk_json_decode_object(val, rpc_core_thread_info_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_core_thread_info_decoders), info);
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:07:22 +00:00
|
|
|
#define RPC_THREAD_ENTRY_SIZE (SPDK_COUNTOF(rpc_core_thread_info_decoders) * 2)
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
static int
|
|
|
|
rpc_decode_cores_lw_threads(const struct spdk_json_val *val, void *out)
|
|
|
|
{
|
|
|
|
struct rpc_core_threads *threads = out;
|
2021-02-16 12:07:22 +00:00
|
|
|
/* The number of thread entries received from RPC can be calculated using
|
|
|
|
* above define value (each JSON line = key + value, hence '* 2' ) and JSON
|
|
|
|
* 'val' value (-2 is to subtract VAL_OBJECT_BEGIN/END). */
|
2022-01-20 08:34:35 +00:00
|
|
|
uint16_t threads_count = (spdk_json_val_len(val) - 2) / RPC_THREAD_ENTRY_SIZE;
|
2021-02-16 12:07:22 +00:00
|
|
|
|
2023-01-09 07:38:45 +00:00
|
|
|
assert(threads != NULL);
|
2021-02-16 12:07:22 +00:00
|
|
|
threads->thread = calloc(threads_count, sizeof(struct rpc_core_thread_info));
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-02-16 12:07:22 +00:00
|
|
|
return spdk_json_decode_array(val, rpc_decode_core_threads_object, threads->thread, threads_count,
|
2020-03-09 12:14:43 +00:00
|
|
|
&threads->threads_count, sizeof(struct rpc_core_thread_info));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct spdk_json_object_decoder rpc_core_info_decoders[] = {
|
|
|
|
{"lcore", offsetof(struct rpc_core_info, lcore), spdk_json_decode_uint32},
|
|
|
|
{"busy", offsetof(struct rpc_core_info, busy), spdk_json_decode_uint64},
|
|
|
|
{"idle", offsetof(struct rpc_core_info, idle), spdk_json_decode_uint64},
|
2021-03-04 11:54:25 +00:00
|
|
|
{"core_freq", offsetof(struct rpc_core_info, core_freq), spdk_json_decode_uint32, true},
|
2021-05-14 09:18:26 +00:00
|
|
|
{"in_interrupt", offsetof(struct rpc_core_info, in_interrupt), spdk_json_decode_bool},
|
2020-03-09 12:14:43 +00:00
|
|
|
{"lw_threads", offsetof(struct rpc_core_info, threads), rpc_decode_cores_lw_threads},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
rpc_decode_core_object(const struct spdk_json_val *val, void *out)
|
|
|
|
{
|
|
|
|
struct rpc_core_info *info = out;
|
|
|
|
|
|
|
|
return spdk_json_decode_object(val, rpc_core_info_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_core_info_decoders), info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-06-28 11:27:00 +00:00
|
|
|
rpc_decode_cores_array(struct spdk_json_val *val, struct rpc_core_info *out,
|
|
|
|
uint32_t *current_cores_count)
|
2020-03-09 12:14:43 +00:00
|
|
|
{
|
2021-06-28 11:27:00 +00:00
|
|
|
struct spdk_json_val *core = val;
|
|
|
|
size_t cores_count;
|
|
|
|
int rc;
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
/* Fetch the beginning of reactors array. */
|
|
|
|
rc = spdk_json_find_array(core, "reactors", NULL, &core);
|
|
|
|
if (rc) {
|
|
|
|
printf("Could not fetch cores array from JSON.");
|
|
|
|
goto end;
|
|
|
|
}
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
rc = spdk_json_decode_array(core, rpc_decode_core_object, out, RPC_MAX_CORES, &cores_count,
|
|
|
|
sizeof(struct rpc_core_info));
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
*current_cores_count = (uint32_t)cores_count;
|
|
|
|
|
|
|
|
end:
|
|
|
|
return rc;
|
|
|
|
}
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-01-15 16:14:16 +00:00
|
|
|
static void
|
|
|
|
free_rpc_scheduler(struct rpc_scheduler *req)
|
|
|
|
{
|
|
|
|
free(req->scheduler_name);
|
2022-04-11 10:24:13 +00:00
|
|
|
free(req->governor_name);
|
2021-01-15 16:14:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct spdk_json_object_decoder rpc_scheduler_decoders[] = {
|
2022-03-01 15:49:50 +00:00
|
|
|
{"scheduler_name", offsetof(struct rpc_scheduler, scheduler_name), spdk_json_decode_string, true},
|
2022-04-11 10:24:13 +00:00
|
|
|
{"governor_name", offsetof(struct rpc_scheduler, governor_name), spdk_json_decode_string, true},
|
2021-01-15 16:14:16 +00:00
|
|
|
{"scheduler_period", offsetof(struct rpc_scheduler, scheduler_period), spdk_json_decode_uint64},
|
|
|
|
};
|
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
static int
|
|
|
|
rpc_send_req(char *rpc_name, struct spdk_jsonrpc_client_response **resp)
|
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
|
|
struct spdk_json_write_ctx *w;
|
|
|
|
struct spdk_jsonrpc_client_request *request;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
request = spdk_jsonrpc_client_create_request();
|
|
|
|
if (request == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
w = spdk_jsonrpc_begin_request(request, 1, rpc_name);
|
|
|
|
spdk_jsonrpc_end_request(request, w);
|
|
|
|
spdk_jsonrpc_client_send_request(g_rpc_client, request);
|
|
|
|
|
|
|
|
do {
|
|
|
|
rc = spdk_jsonrpc_client_poll(g_rpc_client, 1);
|
|
|
|
} while (rc == 0 || rc == -ENOTCONN);
|
|
|
|
|
|
|
|
if (rc <= 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
json_resp = spdk_jsonrpc_client_get_response(g_rpc_client);
|
|
|
|
if (json_resp == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for error response */
|
|
|
|
if (json_resp->error != NULL) {
|
2021-08-26 15:29:09 +00:00
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
2020-04-14 07:01:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(json_resp->result);
|
|
|
|
|
|
|
|
*resp = json_resp;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-16 23:53:50 +00:00
|
|
|
static uint64_t
|
|
|
|
get_cpu_usage(uint64_t busy_ticks, uint64_t idle_ticks)
|
|
|
|
{
|
|
|
|
if (busy_ticks + idle_ticks > 0) {
|
|
|
|
/* Increase numerator to convert fraction into decimal with
|
|
|
|
* additional precision */
|
|
|
|
return busy_ticks * 10000 / (busy_ticks + idle_ticks);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2021-05-18 12:35:10 +00:00
|
|
|
|
|
|
|
static int
|
2021-10-13 16:03:59 +00:00
|
|
|
subsort_threads(enum column_threads_type sort_column, const void *p1, const void *p2)
|
2021-05-18 12:35:10 +00:00
|
|
|
{
|
2021-04-23 11:48:02 +00:00
|
|
|
const struct rpc_thread_info thread_info1 = *(struct rpc_thread_info *)p1;
|
|
|
|
const struct rpc_thread_info thread_info2 = *(struct rpc_thread_info *)p2;
|
2021-05-18 12:35:10 +00:00
|
|
|
uint64_t count1, count2;
|
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
switch (sort_column) {
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_NAME:
|
2021-04-23 11:48:02 +00:00
|
|
|
return strcmp(thread_info1.name, thread_info2.name);
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_CORE:
|
2021-04-23 11:48:02 +00:00
|
|
|
count2 = thread_info1.core_num;
|
|
|
|
count1 = thread_info2.core_num;
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_ACTIVE_POLLERS:
|
2021-04-23 11:48:02 +00:00
|
|
|
count1 = thread_info1.active_pollers_count;
|
|
|
|
count2 = thread_info2.active_pollers_count;
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_TIMED_POLLERS:
|
2021-04-23 11:48:02 +00:00
|
|
|
count1 = thread_info1.timed_pollers_count;
|
|
|
|
count2 = thread_info2.timed_pollers_count;
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_PAUSED_POLLERS:
|
2021-04-23 11:48:02 +00:00
|
|
|
count1 = thread_info1.paused_pollers_count;
|
|
|
|
count2 = thread_info2.paused_pollers_count;
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_IDLE_TIME:
|
2021-07-22 10:55:30 +00:00
|
|
|
if (g_interval_data) {
|
|
|
|
count1 = thread_info1.idle - thread_info1.last_idle;
|
|
|
|
count2 = thread_info2.idle - thread_info2.last_idle;
|
|
|
|
} else {
|
|
|
|
count1 = thread_info1.idle;
|
|
|
|
count2 = thread_info2.idle;
|
|
|
|
}
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_THREADS_BUSY_TIME:
|
2021-07-22 10:55:30 +00:00
|
|
|
if (g_interval_data) {
|
|
|
|
count1 = thread_info1.busy - thread_info1.last_busy;
|
|
|
|
count2 = thread_info2.busy - thread_info2.last_busy;
|
|
|
|
} else {
|
|
|
|
count1 = thread_info1.busy;
|
|
|
|
count2 = thread_info2.busy;
|
|
|
|
}
|
2021-05-18 12:35:10 +00:00
|
|
|
break;
|
2020-12-16 23:53:50 +00:00
|
|
|
case COL_THREADS_CPU_USAGE:
|
|
|
|
count1 = get_cpu_usage(thread_info1.busy - thread_info1.last_busy,
|
|
|
|
g_cores_info[thread_info1.core_num].busy + g_cores_info[thread_info1.core_num].idle);
|
|
|
|
count2 = get_cpu_usage(thread_info2.busy - thread_info2.last_busy,
|
|
|
|
g_cores_info[thread_info2.core_num].busy + g_cores_info[thread_info2.core_num].idle);
|
|
|
|
break;
|
2021-10-13 16:03:59 +00:00
|
|
|
case COL_THREADS_NONE:
|
2021-05-18 12:35:10 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count2 > count1) {
|
|
|
|
return 1;
|
|
|
|
} else if (count2 < count1) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
static int
|
|
|
|
sort_threads(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
res = subsort_threads(g_current_sort_col[THREADS_TAB], p1, p2);
|
|
|
|
if (res == 0) {
|
|
|
|
res = subsort_threads(g_current_sort_col2[THREADS_TAB], p1, p2);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-05-19 10:25:08 +00:00
|
|
|
static void
|
2021-08-05 14:29:55 +00:00
|
|
|
store_last_counters(uint64_t poller_id, uint64_t thread_id, uint64_t last_run_counter,
|
2021-07-13 09:33:33 +00:00
|
|
|
uint64_t last_busy_counter)
|
2021-05-19 10:25:08 +00:00
|
|
|
{
|
|
|
|
struct run_counter_history *history;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(history, &g_run_counter_history, link) {
|
2021-08-05 14:29:55 +00:00
|
|
|
if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
|
2021-05-19 10:25:08 +00:00
|
|
|
history->last_run_counter = last_run_counter;
|
2021-07-13 09:33:33 +00:00
|
|
|
history->last_busy_counter = last_busy_counter;
|
2021-05-19 10:25:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
history = calloc(1, sizeof(*history));
|
|
|
|
if (history == NULL) {
|
2021-07-13 09:33:33 +00:00
|
|
|
fprintf(stderr, "Unable to allocate a history object in store_last_counters.\n");
|
2021-05-19 10:25:08 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-08-05 14:29:55 +00:00
|
|
|
history->poller_id = poller_id;
|
2021-05-19 10:25:08 +00:00
|
|
|
history->thread_id = thread_id;
|
|
|
|
history->last_run_counter = last_run_counter;
|
2021-07-13 09:33:33 +00:00
|
|
|
history->last_busy_counter = last_busy_counter;
|
2021-05-19 10:25:08 +00:00
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&g_run_counter_history, history, link);
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
static int
|
2021-04-14 14:58:11 +00:00
|
|
|
get_thread_data(void)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
2021-06-28 11:42:53 +00:00
|
|
|
struct rpc_thread_info thread_info[RPC_MAX_THREADS], *thread;
|
2021-05-05 13:47:19 +00:00
|
|
|
struct rpc_core_info *core_info;
|
2021-06-28 11:42:53 +00:00
|
|
|
uint64_t i, j, k, current_threads_count = 0;
|
2020-04-14 07:01:41 +00:00
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
rc = rpc_send_req("thread_get_stats", &json_resp);
|
|
|
|
if (rc) {
|
2021-04-14 14:58:11 +00:00
|
|
|
return rc;
|
2020-04-14 07:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Decode json */
|
2021-06-28 11:42:53 +00:00
|
|
|
memset(thread_info, 0, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
|
|
|
|
if (rpc_decode_threads_array(json_resp->result, thread_info, ¤t_threads_count)) {
|
2020-04-14 07:01:41 +00:00
|
|
|
rc = -EINVAL;
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < current_threads_count; i++) {
|
|
|
|
free_rpc_threads_stats(&thread_info[i]);
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
|
2021-04-23 11:48:02 +00:00
|
|
|
/* This is to free allocated char arrays with old thread names */
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < g_last_threads_count; i++) {
|
|
|
|
free_rpc_threads_stats(&g_threads_info[i]);
|
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < current_threads_count; i++) {
|
|
|
|
for (j = 0; j < g_last_threads_count; j++) {
|
|
|
|
if (thread_info[i].id == g_threads_info[j].id) {
|
|
|
|
thread_info[i].last_busy = g_threads_info[j].busy;
|
|
|
|
thread_info[i].last_idle = g_threads_info[j].idle;
|
2021-04-23 11:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-20 11:50:14 +00:00
|
|
|
}
|
2021-06-28 11:42:53 +00:00
|
|
|
g_last_threads_count = current_threads_count;
|
|
|
|
|
|
|
|
memcpy(g_threads_info, thread_info, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
|
2020-04-20 11:50:14 +00:00
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < g_last_threads_count; i++) {
|
|
|
|
g_threads_info[i].core_num = -1;
|
2021-05-05 13:47:19 +00:00
|
|
|
}
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
for (i = 0; i < g_last_cores_count; i++) {
|
|
|
|
core_info = &g_cores_info[i];
|
2021-05-05 13:47:19 +00:00
|
|
|
|
|
|
|
for (j = 0; j < core_info->threads.threads_count; j++) {
|
2021-06-28 11:42:53 +00:00
|
|
|
for (k = 0; k < g_last_threads_count; k++) {
|
2021-05-05 13:47:19 +00:00
|
|
|
/* For each thread on current core: check if it's ID also exists
|
|
|
|
* in g_thread_info data structure. If it does then assign current
|
|
|
|
* core's number to that thread, otherwise application state is inconsistent
|
|
|
|
* (e.g. scheduler is moving threads between cores). */
|
2021-06-28 11:42:53 +00:00
|
|
|
thread = &g_threads_info[k];
|
|
|
|
if (thread->id == core_info->threads.thread[j].id) {
|
|
|
|
thread->core_num = core_info->lcore;
|
2021-05-05 13:47:19 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
qsort(g_threads_info, g_last_threads_count, sizeof(struct rpc_thread_info), sort_threads);
|
2021-07-02 13:23:56 +00:00
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
|
|
|
|
end:
|
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-05-25 09:01:13 +00:00
|
|
|
static uint64_t
|
2021-08-05 14:29:55 +00:00
|
|
|
get_last_run_counter(uint64_t poller_id, uint64_t thread_id)
|
2021-05-25 09:01:13 +00:00
|
|
|
{
|
|
|
|
struct run_counter_history *history;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(history, &g_run_counter_history, link) {
|
2021-08-05 14:29:55 +00:00
|
|
|
if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
|
2021-05-25 09:01:13 +00:00
|
|
|
return history->last_run_counter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t
|
2021-08-05 14:29:55 +00:00
|
|
|
get_last_busy_counter(uint64_t poller_id, uint64_t thread_id)
|
2021-05-25 09:01:13 +00:00
|
|
|
{
|
|
|
|
struct run_counter_history *history;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(history, &g_run_counter_history, link) {
|
2021-08-05 14:29:55 +00:00
|
|
|
if ((history->poller_id == poller_id) && (history->thread_id == thread_id)) {
|
2021-05-25 09:01:13 +00:00
|
|
|
return history->last_busy_counter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-10-13 16:03:59 +00:00
|
|
|
subsort_pollers(enum column_pollers_type sort_column, const void *p1, const void *p2)
|
2021-05-25 09:01:13 +00:00
|
|
|
{
|
2021-07-05 10:59:51 +00:00
|
|
|
const struct rpc_poller_info *poller1 = (struct rpc_poller_info *)p1;
|
|
|
|
const struct rpc_poller_info *poller2 = (struct rpc_poller_info *)p2;
|
2021-05-25 09:01:13 +00:00
|
|
|
uint64_t count1, count2;
|
2021-11-03 15:19:26 +00:00
|
|
|
uint64_t last_busy_counter1, last_busy_counter2;
|
2021-05-25 09:01:13 +00:00
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
switch (sort_column) {
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_POLLERS_NAME:
|
2021-05-25 09:01:13 +00:00
|
|
|
return strcmp(poller1->name, poller2->name);
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_POLLERS_TYPE:
|
|
|
|
return poller1->type - poller2->type;
|
|
|
|
case COL_POLLERS_THREAD_NAME:
|
|
|
|
return strcmp(poller1->thread_name, poller2->thread_name);
|
|
|
|
case COL_POLLERS_RUN_COUNTER:
|
|
|
|
if (g_interval_data) {
|
2021-08-05 14:29:55 +00:00
|
|
|
count1 = poller1->run_count - get_last_run_counter(poller1->id, poller1->thread_id);
|
|
|
|
count2 = poller2->run_count - get_last_run_counter(poller2->id, poller2->thread_id);
|
2021-11-03 17:22:59 +00:00
|
|
|
} else {
|
|
|
|
count1 = poller1->run_count;
|
|
|
|
count2 = poller2->run_count;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case COL_POLLERS_PERIOD:
|
|
|
|
count1 = poller1->period_ticks;
|
|
|
|
count2 = poller2->period_ticks;
|
|
|
|
break;
|
|
|
|
case COL_POLLERS_BUSY_COUNT:
|
|
|
|
count1 = poller1->busy_count;
|
|
|
|
count2 = poller2->busy_count;
|
|
|
|
if (g_interval_data) {
|
2021-08-05 14:29:55 +00:00
|
|
|
last_busy_counter1 = get_last_busy_counter(poller1->id, poller1->thread_id);
|
|
|
|
last_busy_counter2 = get_last_busy_counter(poller2->id, poller2->thread_id);
|
2021-11-03 17:22:59 +00:00
|
|
|
if (count1 > last_busy_counter1) {
|
|
|
|
count1 -= last_busy_counter1;
|
2021-07-22 10:55:30 +00:00
|
|
|
}
|
2021-11-03 17:22:59 +00:00
|
|
|
if (count2 > last_busy_counter2) {
|
|
|
|
count2 -= last_busy_counter2;
|
2021-11-03 15:19:26 +00:00
|
|
|
}
|
2021-05-25 09:01:13 +00:00
|
|
|
}
|
2021-11-03 17:22:59 +00:00
|
|
|
break;
|
2021-10-13 16:03:59 +00:00
|
|
|
case COL_POLLERS_NONE:
|
2021-11-03 17:22:59 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
2021-05-25 09:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count2 > count1) {
|
|
|
|
return 1;
|
|
|
|
} else if (count2 < count1) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
static int
|
2021-11-03 23:48:10 +00:00
|
|
|
sort_pollers(const void *p1, const void *p2)
|
2021-10-13 16:03:59 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = subsort_pollers(g_current_sort_col[POLLERS_TAB], p1, p2);
|
|
|
|
if (rc == 0) {
|
|
|
|
rc = subsort_pollers(g_current_sort_col2[POLLERS_TAB], p1, p2);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
static int
|
|
|
|
get_pollers_data(void)
|
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
|
|
int rc = 0;
|
2021-06-22 11:44:20 +00:00
|
|
|
uint64_t i = 0;
|
2021-06-02 08:12:29 +00:00
|
|
|
uint32_t current_pollers_count;
|
|
|
|
struct rpc_poller_info pollers_info[RPC_MAX_POLLERS];
|
2021-04-14 14:58:11 +00:00
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
rc = rpc_send_req("thread_get_pollers", &json_resp);
|
|
|
|
if (rc) {
|
2021-04-14 14:58:11 +00:00
|
|
|
return rc;
|
2020-04-14 07:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 08:12:29 +00:00
|
|
|
/* Decode json */
|
|
|
|
memset(&pollers_info, 0, sizeof(pollers_info));
|
|
|
|
if (rpc_decode_pollers_threads_array(json_resp->result, pollers_info, ¤t_pollers_count)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
for (i = 0; i < current_pollers_count; i++) {
|
|
|
|
free_rpc_poller(&pollers_info[i]);
|
|
|
|
}
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
/* Save last run counter of each poller before updating g_pollers_stats. */
|
|
|
|
for (i = 0; i < g_last_pollers_count; i++) {
|
2021-08-05 14:29:55 +00:00
|
|
|
store_last_counters(g_pollers_info[i].id, g_pollers_info[i].thread_id,
|
2021-07-13 09:33:33 +00:00
|
|
|
g_pollers_info[i].run_count, g_pollers_info[i].busy_count);
|
2021-05-19 10:08:59 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 10:58:35 +00:00
|
|
|
/* Free old pollers values before allocating memory for new ones */
|
2021-06-22 11:44:20 +00:00
|
|
|
for (i = 0; i < g_last_pollers_count; i++) {
|
|
|
|
free_rpc_poller(&g_pollers_info[i]);
|
|
|
|
}
|
2021-05-19 10:58:35 +00:00
|
|
|
|
2021-06-02 08:12:29 +00:00
|
|
|
g_last_pollers_count = current_pollers_count;
|
|
|
|
|
2021-11-03 23:48:10 +00:00
|
|
|
qsort(&pollers_info, g_last_pollers_count, sizeof(struct rpc_poller_info), sort_pollers);
|
2021-07-05 10:59:51 +00:00
|
|
|
|
2021-06-02 08:12:29 +00:00
|
|
|
memcpy(&g_pollers_info, &pollers_info, sizeof(struct rpc_poller_info) * g_last_pollers_count);
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2021-06-02 08:12:29 +00:00
|
|
|
|
|
|
|
end:
|
2020-03-09 12:14:43 +00:00
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
2021-04-14 14:58:11 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:07:22 +00:00
|
|
|
static int
|
2021-10-13 16:03:59 +00:00
|
|
|
subsort_cores(enum column_cores_type sort_column, const void *p1, const void *p2)
|
2021-02-16 12:07:22 +00:00
|
|
|
{
|
|
|
|
const struct rpc_core_info core_info1 = *(struct rpc_core_info *)p1;
|
|
|
|
const struct rpc_core_info core_info2 = *(struct rpc_core_info *)p2;
|
|
|
|
uint64_t count1, count2;
|
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
switch (sort_column) {
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_CORE:
|
2021-02-16 12:07:22 +00:00
|
|
|
count1 = core_info2.lcore;
|
|
|
|
count2 = core_info1.lcore;
|
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_THREADS:
|
2021-06-28 11:27:00 +00:00
|
|
|
count1 = core_info1.threads.threads_count;
|
|
|
|
count2 = core_info2.threads.threads_count;
|
2021-02-16 12:07:22 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_POLLERS:
|
2021-02-16 12:07:22 +00:00
|
|
|
count1 = core_info1.pollers_count;
|
|
|
|
count2 = core_info2.pollers_count;
|
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_IDLE_TIME:
|
2021-07-22 10:55:30 +00:00
|
|
|
if (g_interval_data) {
|
|
|
|
count1 = core_info1.last_idle - core_info1.idle;
|
|
|
|
count2 = core_info2.last_idle - core_info2.idle;
|
|
|
|
} else {
|
|
|
|
count1 = core_info1.idle;
|
|
|
|
count2 = core_info2.idle;
|
|
|
|
}
|
2021-02-16 12:07:22 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_BUSY_TIME:
|
2021-07-22 10:55:30 +00:00
|
|
|
if (g_interval_data) {
|
|
|
|
count1 = core_info1.last_busy - core_info1.busy;
|
|
|
|
count2 = core_info2.last_busy - core_info2.busy;
|
|
|
|
} else {
|
|
|
|
count1 = core_info1.busy;
|
|
|
|
count2 = core_info2.busy;
|
|
|
|
}
|
2021-02-16 12:07:22 +00:00
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_CORE_FREQ:
|
2021-11-03 15:19:26 +00:00
|
|
|
count1 = core_info1.core_freq;
|
|
|
|
count2 = core_info2.core_freq;
|
|
|
|
break;
|
2021-11-03 17:22:59 +00:00
|
|
|
case COL_CORES_INTR:
|
2021-11-03 15:19:26 +00:00
|
|
|
count1 = core_info1.in_interrupt;
|
|
|
|
count2 = core_info2.in_interrupt;
|
|
|
|
break;
|
2020-12-16 23:53:50 +00:00
|
|
|
case COL_CORES_CPU_USAGE:
|
|
|
|
count1 = get_cpu_usage(core_info1.last_busy - core_info1.busy,
|
|
|
|
core_info1.last_idle - core_info1.idle);
|
|
|
|
count2 = get_cpu_usage(core_info2.last_busy - core_info2.busy,
|
|
|
|
core_info2.last_idle - core_info2.idle);
|
|
|
|
break;
|
2021-10-13 16:03:59 +00:00
|
|
|
case COL_CORES_NONE:
|
2021-02-16 12:07:22 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count2 > count1) {
|
|
|
|
return 1;
|
|
|
|
} else if (count2 < count1) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:03:59 +00:00
|
|
|
static int
|
|
|
|
sort_cores(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = subsort_cores(g_current_sort_col[CORES_TAB], p1, p2);
|
|
|
|
if (rc == 0) {
|
|
|
|
return subsort_cores(g_current_sort_col[CORES_TAB], p1, p2);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
static int
|
|
|
|
get_cores_data(void)
|
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
|
|
struct rpc_core_info *core_info;
|
|
|
|
uint64_t i, j, k;
|
2021-06-28 11:27:00 +00:00
|
|
|
uint32_t current_cores_count;
|
|
|
|
struct rpc_core_info cores_info[RPC_MAX_CORES];
|
2021-04-14 14:58:11 +00:00
|
|
|
int rc = 0;
|
2020-03-09 12:14:43 +00:00
|
|
|
|
|
|
|
rc = rpc_send_req("framework_get_reactors", &json_resp);
|
|
|
|
if (rc) {
|
2021-04-14 14:58:11 +00:00
|
|
|
return rc;
|
2020-03-09 12:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Decode json */
|
2021-06-28 11:27:00 +00:00
|
|
|
memset(cores_info, 0, sizeof(struct rpc_core_info) * RPC_MAX_CORES);
|
|
|
|
if (rpc_decode_cores_array(json_resp->result, cores_info, ¤t_cores_count)) {
|
2020-03-09 12:14:43 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:07:22 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-06-28 11:27:00 +00:00
|
|
|
for (i = 0; i < current_cores_count; i++) {
|
|
|
|
for (j = 0; j < g_last_cores_count; j++) {
|
2021-10-14 14:13:39 +00:00
|
|
|
if (cores_info[i].lcore == g_cores_info[j].lcore) {
|
|
|
|
cores_info[i].last_busy = g_cores_info[j].busy;
|
|
|
|
cores_info[i].last_idle = g_cores_info[j].idle;
|
|
|
|
}
|
2021-06-28 11:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-16 12:07:22 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
/* Free old cores values before allocating memory for new ones */
|
|
|
|
free_rpc_core_info(g_cores_info, current_cores_count);
|
|
|
|
memcpy(g_cores_info, cores_info, sizeof(struct rpc_core_info) * current_cores_count);
|
2021-02-16 12:07:22 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
for (i = 0; i < g_last_cores_count; i++) {
|
|
|
|
core_info = &g_cores_info[i];
|
2020-04-20 11:50:14 +00:00
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
core_info->threads.thread = cores_info[i].threads.thread;
|
2021-02-16 12:07:22 +00:00
|
|
|
|
2020-04-20 11:50:14 +00:00
|
|
|
for (j = 0; j < core_info->threads.threads_count; j++) {
|
2021-06-28 11:27:00 +00:00
|
|
|
memcpy(&core_info->threads.thread[j], &cores_info[i].threads.thread[j],
|
|
|
|
sizeof(struct rpc_core_thread_info));
|
2021-06-28 11:42:53 +00:00
|
|
|
for (k = 0; k < g_last_threads_count; k++) {
|
|
|
|
if (core_info->threads.thread[j].id == g_threads_info[k].id) {
|
|
|
|
g_threads_info[k].core_num = core_info->lcore;
|
2022-07-07 07:51:51 +00:00
|
|
|
/* Do not consider threads which changed cores when issuing
|
|
|
|
* RPCs to get_core_data and get_thread_data and threads
|
|
|
|
* not currently assigned to this core. */
|
|
|
|
core_info->pollers_count += g_threads_info[k].active_pollers_count +
|
|
|
|
g_threads_info[k].timed_pollers_count +
|
|
|
|
g_threads_info[k].paused_pollers_count;
|
2021-06-02 07:15:18 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-20 11:50:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
g_last_cores_count = current_cores_count;
|
|
|
|
|
|
|
|
qsort(&g_cores_info, g_last_cores_count, sizeof(struct rpc_core_info), sort_cores);
|
2021-02-16 12:07:22 +00:00
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
end:
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-04-14 07:01:41 +00:00
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-01-15 16:14:16 +00:00
|
|
|
static int
|
|
|
|
get_scheduler_data(void)
|
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
|
|
struct rpc_scheduler scheduler_info;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
rc = rpc_send_req("framework_get_scheduler", &json_resp);
|
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&scheduler_info, 0, sizeof(scheduler_info));
|
2022-03-22 09:39:31 +00:00
|
|
|
if (spdk_json_decode_object_relaxed(json_resp->result, rpc_scheduler_decoders,
|
|
|
|
SPDK_COUNTOF(rpc_scheduler_decoders), &scheduler_info)) {
|
2021-01-15 16:14:16 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
} else {
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
|
|
|
|
free_rpc_scheduler(&g_scheduler_info);
|
|
|
|
|
|
|
|
memcpy(&g_scheduler_info, &scheduler_info, sizeof(struct rpc_scheduler));
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-03-23 09:48:04 +00:00
|
|
|
enum str_alignment {
|
|
|
|
ALIGN_LEFT,
|
|
|
|
ALIGN_RIGHT,
|
|
|
|
};
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
static void
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(WINDOW *win, int row, uint16_t col, uint16_t max_len, enum str_alignment alignment,
|
|
|
|
const char *string)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-03-06 13:34:59 +00:00
|
|
|
const char dots[] = "...";
|
|
|
|
int DOTS_STR_LEN = sizeof(dots) / sizeof(dots[0]);
|
2020-03-23 09:48:04 +00:00
|
|
|
char tmp_str[MAX_STRING_LEN];
|
|
|
|
int len, max_col, max_str, cmp_len;
|
2020-03-09 12:14:43 +00:00
|
|
|
int max_row;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
len = strlen(string);
|
|
|
|
getmaxyx(win, max_row, max_col);
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
if (row > max_row) {
|
|
|
|
/* We are in a process of resizing and this may happen */
|
|
|
|
return;
|
|
|
|
}
|
2020-02-28 13:00:08 +00:00
|
|
|
|
2020-03-06 13:34:59 +00:00
|
|
|
if (max_len != 0 && col + max_len < max_col) {
|
|
|
|
max_col = col + max_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_str = max_col - col;
|
|
|
|
|
2020-03-23 09:48:04 +00:00
|
|
|
if (max_str <= DOTS_STR_LEN + 1) {
|
|
|
|
/* No space to print anything, but we have to let a user know about it */
|
|
|
|
mvwprintw(win, row, max_col - DOTS_STR_LEN - 1, "...");
|
2022-01-24 15:43:28 +00:00
|
|
|
wnoutrefresh(win);
|
2020-03-06 13:34:59 +00:00
|
|
|
return;
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-23 09:48:04 +00:00
|
|
|
if (max_len) {
|
|
|
|
if (alignment == ALIGN_LEFT) {
|
2020-03-06 13:34:59 +00:00
|
|
|
snprintf(tmp_str, max_str, "%s%*c", string, max_len - len - 1, ' ');
|
|
|
|
} else {
|
2020-03-23 09:48:04 +00:00
|
|
|
snprintf(tmp_str, max_str, "%*c%s", max_len - len - 1, ' ', string);
|
2020-03-06 13:34:59 +00:00
|
|
|
}
|
2020-03-23 09:48:04 +00:00
|
|
|
cmp_len = max_len - 1;
|
|
|
|
} else {
|
|
|
|
snprintf(tmp_str, max_str, "%s", string);
|
|
|
|
cmp_len = len;
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
2020-03-23 09:48:04 +00:00
|
|
|
|
|
|
|
if (col + cmp_len > max_col - 1) {
|
|
|
|
snprintf(&tmp_str[max_str - DOTS_STR_LEN - 2], DOTS_STR_LEN, "%s", dots);
|
|
|
|
}
|
|
|
|
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(win, row, col, "%s", tmp_str);
|
2020-03-23 09:48:04 +00:00
|
|
|
|
2022-01-24 15:43:28 +00:00
|
|
|
wnoutrefresh(win);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_menu_win(void)
|
|
|
|
{
|
|
|
|
wbkgd(g_menu_win, COLOR_PAIR(2));
|
|
|
|
box(g_menu_win, 0, 0);
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(g_menu_win, 1, 1, 0, ALIGN_LEFT,
|
2021-01-28 08:43:41 +00:00
|
|
|
" [q] Quit | [1-3][Tab] Switch tab | [PgUp] Previous page | [PgDown] Next page | [Enter] Item details | [h] Help");
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_tab_win(enum tabs tab)
|
|
|
|
{
|
|
|
|
uint16_t col;
|
|
|
|
uint8_t white_spaces = TABS_SPACING * NUMBER_OF_TABS;
|
|
|
|
|
2022-11-25 10:31:14 +00:00
|
|
|
wbkgd(g_tab_win[tab], COLOR_PAIR(10));
|
2020-02-28 13:00:08 +00:00
|
|
|
box(g_tab_win[tab], 0, 0);
|
|
|
|
|
|
|
|
col = ((g_max_col - white_spaces) / NUMBER_OF_TABS / 2) - (strlen(g_tab_title[tab]) / 2) -
|
|
|
|
TABS_SPACING;
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(g_tab_win[tab], 1, col, 0, ALIGN_LEFT, g_tab_title[tab]);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(enum tabs tab_index, uint8_t sort_col, uint8_t sort_col2)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-04-20 09:14:19 +00:00
|
|
|
struct col_desc *col_desc = g_col_desc[tab_index];
|
|
|
|
WINDOW *tab = g_tabs[tab_index];
|
2020-03-27 09:13:14 +00:00
|
|
|
int i, j;
|
2020-03-05 07:57:27 +00:00
|
|
|
uint16_t offset, draw_offset;
|
2021-09-06 08:54:58 +00:00
|
|
|
uint16_t tab_height = g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 3;
|
2020-03-27 09:13:14 +00:00
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
for (i = 0; col_desc[i].name != NULL; i++) {
|
|
|
|
if (col_desc[i].disabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
offset = 1;
|
|
|
|
for (j = i; j != 0; j--) {
|
2020-03-05 07:57:27 +00:00
|
|
|
if (!col_desc[j - 1].disabled) {
|
|
|
|
offset += col_desc[j - 1].max_data_string;
|
|
|
|
offset += col_desc[j - 1].name_len % 2 + 1;
|
|
|
|
}
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 07:57:27 +00:00
|
|
|
draw_offset = offset + (col_desc[i].max_data_string / 2) - (col_desc[i].name_len / 2);
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
if (i == sort_col) {
|
2021-10-13 16:21:58 +00:00
|
|
|
wattron(tab, COLOR_PAIR(4));
|
|
|
|
print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
|
|
|
|
wattroff(tab, COLOR_PAIR(4));
|
|
|
|
} else if (i == sort_col2) {
|
2020-04-20 09:14:19 +00:00
|
|
|
wattron(tab, COLOR_PAIR(3));
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
|
2020-04-20 09:14:19 +00:00
|
|
|
wattroff(tab, COLOR_PAIR(3));
|
2020-03-27 09:13:14 +00:00
|
|
|
} else {
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(tab, 1, draw_offset, 0, ALIGN_LEFT, col_desc[i].name);
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 07:57:27 +00:00
|
|
|
if (offset != 1) {
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(tab, 1, offset - 1, 0, ALIGN_LEFT, "|");
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-28 13:00:08 +00:00
|
|
|
|
2020-03-23 09:48:04 +00:00
|
|
|
print_max_len(tab, 2, 1, 0, ALIGN_LEFT, ""); /* Move to next line */
|
2021-09-06 08:54:58 +00:00
|
|
|
whline(tab, ACS_HLINE, g_max_col - 2);
|
|
|
|
|
|
|
|
/* Border lines */
|
|
|
|
mvwhline(tab, 0, 1, ACS_HLINE, g_max_col - 2);
|
|
|
|
mvwhline(tab, tab_height, 1, ACS_HLINE, g_max_col - 2);
|
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
wrefresh(tab);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
resize_interface(enum tabs tab)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
clear();
|
|
|
|
wclear(g_menu_win);
|
|
|
|
mvwin(g_menu_win, g_max_row - MENU_WIN_SPACING, MENU_WIN_LOCATION_COL);
|
|
|
|
wresize(g_menu_win, MENU_WIN_HEIGHT, g_max_col);
|
|
|
|
draw_menu_win();
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
wclear(g_tabs[i]);
|
|
|
|
wresize(g_tabs[i], g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 2, g_max_col);
|
|
|
|
mvwin(g_tabs[i], TABS_LOCATION_ROW, TABS_LOCATION_COL);
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
wclear(g_tab_win[i]);
|
|
|
|
wresize(g_tab_win[i], TAB_WIN_HEIGHT,
|
|
|
|
(g_max_col - (TABS_SPACING * NUMBER_OF_TABS)) / NUMBER_OF_TABS);
|
|
|
|
mvwin(g_tab_win[i], TAB_WIN_LOCATION_ROW, 1 + (g_max_col / NUMBER_OF_TABS) * i);
|
|
|
|
draw_tab_win(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
switch_tab(enum tabs tab)
|
|
|
|
{
|
2021-08-26 15:01:06 +00:00
|
|
|
wclear(g_tabs[tab]);
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
|
2020-03-27 09:13:14 +00:00
|
|
|
top_panel(g_panels[tab]);
|
2020-02-28 13:00:08 +00:00
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
}
|
|
|
|
|
2020-04-16 13:34:15 +00:00
|
|
|
static void
|
|
|
|
get_time_str(uint64_t ticks, char *time_str)
|
|
|
|
{
|
|
|
|
uint64_t time;
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
time = ticks * SPDK_SEC_TO_USEC / g_tick_rate;
|
2020-04-16 13:34:15 +00:00
|
|
|
snprintf(time_str, MAX_TIME_STR_LEN, "%" PRIu64, time);
|
|
|
|
}
|
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
static void
|
|
|
|
draw_row_background(uint8_t item_index, uint8_t tab)
|
|
|
|
{
|
|
|
|
int k;
|
|
|
|
|
|
|
|
if (item_index == g_selected_row) {
|
|
|
|
wattron(g_tabs[tab], COLOR_PAIR(2));
|
|
|
|
}
|
|
|
|
for (k = 1; k < g_max_col - 1; k++) {
|
|
|
|
mvwprintw(g_tabs[tab], TABS_DATA_START_ROW + item_index, k, " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 23:53:50 +00:00
|
|
|
static void
|
|
|
|
get_cpu_usage_str(uint64_t busy_ticks, uint64_t total_ticks, char *cpu_str)
|
|
|
|
{
|
|
|
|
if (total_ticks > 0) {
|
|
|
|
snprintf(cpu_str, MAX_CPU_STR_LEN, "%.2f",
|
|
|
|
(double)(busy_ticks) * 100 / (double)(total_ticks));
|
|
|
|
} else {
|
|
|
|
cpu_str[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
static void
|
|
|
|
draw_thread_tab_row(uint64_t current_row, uint8_t item_index)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-04-20 09:14:19 +00:00
|
|
|
struct col_desc *col_desc = g_col_desc[THREADS_TAB];
|
2021-11-22 13:28:20 +00:00
|
|
|
uint16_t col = TABS_DATA_START_COL;
|
2021-06-17 10:01:39 +00:00
|
|
|
int core_num, color_attr = COLOR_PAIR(6);
|
2020-03-06 08:52:40 +00:00
|
|
|
char pollers_number[MAX_POLLER_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN],
|
2020-12-16 23:53:50 +00:00
|
|
|
busy_time[MAX_TIME_STR_LEN], core_str[MAX_CORE_MASK_STR_LEN],
|
2021-06-17 10:01:39 +00:00
|
|
|
cpu_usage[MAX_CPU_STR_LEN], *status_str;
|
2020-03-27 09:13:14 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_THREADS_NAME].disabled) {
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_THREADS_NAME].max_data_string, ALIGN_LEFT, g_threads_info[current_row].name);
|
|
|
|
col += col_desc[COL_THREADS_NAME].max_data_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_CORE].disabled) {
|
|
|
|
snprintf(core_str, MAX_CORE_STR_LEN, "%d", g_threads_info[current_row].core_num);
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col, col_desc[COL_THREADS_CORE].max_data_string, ALIGN_RIGHT, core_str);
|
|
|
|
col += col_desc[COL_THREADS_CORE].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_ACTIVE_POLLERS].disabled) {
|
|
|
|
snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld",
|
|
|
|
g_threads_info[current_row].active_pollers_count);
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_THREADS_ACTIVE_POLLERS].name_len / 2),
|
|
|
|
col_desc[COL_THREADS_ACTIVE_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
|
|
|
|
col += col_desc[COL_THREADS_ACTIVE_POLLERS].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_TIMED_POLLERS].disabled) {
|
|
|
|
snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld",
|
|
|
|
g_threads_info[current_row].timed_pollers_count);
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_THREADS_TIMED_POLLERS].name_len / 2),
|
|
|
|
col_desc[COL_THREADS_TIMED_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
|
|
|
|
col += col_desc[COL_THREADS_TIMED_POLLERS].max_data_string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_PAUSED_POLLERS].disabled) {
|
|
|
|
snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld",
|
|
|
|
g_threads_info[current_row].paused_pollers_count);
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_THREADS_PAUSED_POLLERS].name_len / 2),
|
|
|
|
col_desc[COL_THREADS_PAUSED_POLLERS].max_data_string, ALIGN_LEFT, pollers_number);
|
|
|
|
col += col_desc[COL_THREADS_PAUSED_POLLERS].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
2022-12-06 05:49:31 +00:00
|
|
|
uint64_t idle_period = g_threads_info[current_row].idle - g_threads_info[current_row].last_idle;
|
|
|
|
uint64_t busy_period = g_threads_info[current_row].busy - g_threads_info[current_row].last_busy;
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_THREADS_IDLE_TIME].disabled) {
|
|
|
|
if (g_interval_data == true) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_time_str(idle_period, idle_time);
|
2021-11-22 13:28:20 +00:00
|
|
|
} else {
|
|
|
|
get_time_str(g_threads_info[current_row].idle, idle_time);
|
|
|
|
}
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_THREADS_IDLE_TIME].max_data_string, ALIGN_RIGHT, idle_time);
|
|
|
|
col += col_desc[COL_THREADS_IDLE_TIME].max_data_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_BUSY_TIME].disabled) {
|
|
|
|
if (g_interval_data == true) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_time_str(busy_period, busy_time);
|
2021-11-22 13:28:20 +00:00
|
|
|
} else {
|
|
|
|
get_time_str(g_threads_info[current_row].busy, busy_time);
|
|
|
|
}
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_THREADS_BUSY_TIME].max_data_string, ALIGN_RIGHT, busy_time);
|
|
|
|
col += col_desc[COL_THREADS_BUSY_TIME].max_data_string + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_CPU_USAGE].disabled) {
|
|
|
|
core_num = g_threads_info[current_row].core_num;
|
2022-12-06 05:49:31 +00:00
|
|
|
uint64_t core_busy_period = g_cores_info[core_num].busy - g_cores_info[core_num].last_busy;
|
|
|
|
uint64_t core_idle_period = g_cores_info[core_num].idle - g_cores_info[core_num].last_idle;
|
2021-11-22 13:28:20 +00:00
|
|
|
if (core_num >= 0 && core_num < RPC_MAX_CORES) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_cpu_usage_str(busy_period, core_busy_period + core_idle_period, cpu_usage);
|
2021-11-22 13:28:20 +00:00
|
|
|
} else {
|
|
|
|
snprintf(cpu_usage, sizeof(cpu_usage), "n/a");
|
|
|
|
}
|
|
|
|
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_THREADS_CPU_USAGE].max_data_string, ALIGN_RIGHT, cpu_usage);
|
2021-06-17 10:01:39 +00:00
|
|
|
col += col_desc[COL_THREADS_CPU_USAGE].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_THREADS_STATUS].disabled) {
|
2022-12-06 05:49:31 +00:00
|
|
|
if (busy_period > idle_period) {
|
2021-06-17 10:01:39 +00:00
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
color_attr = COLOR_PAIR(6);
|
|
|
|
} else {
|
|
|
|
color_attr = COLOR_PAIR(8);
|
|
|
|
}
|
|
|
|
status_str = "Busy";
|
|
|
|
} else {
|
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
color_attr = COLOR_PAIR(7);
|
|
|
|
} else {
|
|
|
|
color_attr = COLOR_PAIR(9);
|
|
|
|
}
|
|
|
|
status_str = "Idle";
|
|
|
|
}
|
|
|
|
wattron(g_tabs[THREADS_TAB], color_attr);
|
|
|
|
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_THREADS_STATUS].max_data_string, ALIGN_RIGHT, status_str);
|
|
|
|
wattroff(g_tabs[THREADS_TAB], color_attr);
|
2021-11-22 13:28:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
refresh_threads_tab(uint8_t current_page)
|
|
|
|
{
|
|
|
|
uint64_t i, j, threads_count;
|
|
|
|
uint16_t empty_col = 0;
|
|
|
|
uint8_t max_pages, item_index;
|
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
threads_count = g_last_threads_count;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
max_pages = (threads_count + g_max_data_rows - 1) / g_max_data_rows;
|
|
|
|
|
|
|
|
for (i = current_page * g_max_data_rows;
|
2021-08-17 08:52:45 +00:00
|
|
|
i < (uint64_t)((current_page + 1) * g_max_data_rows);
|
2020-03-09 12:14:43 +00:00
|
|
|
i++) {
|
|
|
|
item_index = i - (current_page * g_max_data_rows);
|
|
|
|
|
2021-08-17 08:52:45 +00:00
|
|
|
/* When number of threads decreases, this will print spaces in places
|
|
|
|
* where non existent threads were previously displayed. */
|
|
|
|
if (i >= threads_count) {
|
|
|
|
for (j = 1; j < (uint64_t)g_max_col - 1; j++) {
|
|
|
|
mvwprintw(g_tabs[THREADS_TAB], item_index + TABS_DATA_START_ROW, j, " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
empty_col++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
draw_row_background(item_index, THREADS_TAB);
|
2021-11-22 13:28:20 +00:00
|
|
|
draw_thread_tab_row(i, item_index);
|
2020-04-07 10:44:59 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (item_index == g_selected_row) {
|
|
|
|
wattroff(g_tabs[THREADS_TAB], COLOR_PAIR(2));
|
2020-04-20 09:14:19 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
}
|
2020-03-27 09:13:14 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
g_max_selected_row = i - current_page * g_max_data_rows - 1 - empty_col;
|
2020-04-20 09:30:15 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
return max_pages;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_poller_tab_row(uint64_t current_row, uint8_t item_index)
|
|
|
|
{
|
|
|
|
struct col_desc *col_desc = g_col_desc[POLLERS_TAB];
|
|
|
|
uint64_t last_run_counter, last_busy_counter;
|
|
|
|
uint16_t col = TABS_DATA_START_COL;
|
|
|
|
char run_count[MAX_POLLER_RUN_COUNT], period_ticks[MAX_PERIOD_STR_LEN],
|
|
|
|
status[MAX_POLLER_IND_STR_LEN];
|
|
|
|
|
|
|
|
last_busy_counter = get_last_busy_counter(g_pollers_info[current_row].id,
|
|
|
|
g_pollers_info[current_row].thread_id);
|
2020-04-20 09:30:15 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_POLLERS_NAME].disabled) {
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col + 1,
|
|
|
|
col_desc[COL_POLLERS_NAME].max_data_string, ALIGN_LEFT, g_pollers_info[current_row].name);
|
|
|
|
col += col_desc[COL_POLLERS_NAME].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_POLLERS_TYPE].disabled) {
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_TYPE].max_data_string, ALIGN_LEFT,
|
|
|
|
poller_type_str[g_pollers_info[current_row].type]);
|
|
|
|
col += col_desc[COL_POLLERS_TYPE].max_data_string + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_POLLERS_THREAD_NAME].disabled) {
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_THREAD_NAME].max_data_string, ALIGN_LEFT,
|
|
|
|
g_pollers_info[current_row].thread_name);
|
|
|
|
col += col_desc[COL_POLLERS_THREAD_NAME].max_data_string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_POLLERS_RUN_COUNTER].disabled) {
|
|
|
|
last_run_counter = get_last_run_counter(g_pollers_info[current_row].id,
|
|
|
|
g_pollers_info[current_row].thread_id);
|
|
|
|
if (g_interval_data == true) {
|
|
|
|
snprintf(run_count, MAX_POLLER_RUN_COUNT, "%" PRIu64,
|
|
|
|
g_pollers_info[current_row].run_count - last_run_counter);
|
|
|
|
} else {
|
|
|
|
snprintf(run_count, MAX_POLLER_RUN_COUNT, "%" PRIu64, g_pollers_info[current_row].run_count);
|
2020-04-20 09:30:15 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_RUN_COUNTER].max_data_string, ALIGN_RIGHT, run_count);
|
|
|
|
col += col_desc[COL_POLLERS_RUN_COUNTER].max_data_string;
|
|
|
|
}
|
2020-04-20 09:30:15 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_POLLERS_PERIOD].disabled) {
|
|
|
|
if (g_pollers_info[current_row].period_ticks != 0) {
|
|
|
|
get_time_str(g_pollers_info[current_row].period_ticks, period_ticks);
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_PERIOD].max_data_string, ALIGN_RIGHT, period_ticks);
|
2020-03-06 08:52:40 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
col += col_desc[COL_POLLERS_PERIOD].max_data_string + 7;
|
|
|
|
}
|
2020-03-06 08:52:40 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_POLLERS_BUSY_COUNT].disabled) {
|
|
|
|
if (g_pollers_info[current_row].busy_count > last_busy_counter) {
|
2020-12-09 09:42:49 +00:00
|
|
|
if (g_interval_data == true) {
|
2021-11-22 13:28:20 +00:00
|
|
|
snprintf(status, MAX_POLLER_IND_STR_LEN, "Busy (%" PRIu64 ")",
|
|
|
|
g_pollers_info[current_row].busy_count - last_busy_counter);
|
2020-12-09 09:42:49 +00:00
|
|
|
} else {
|
2021-11-22 13:28:20 +00:00
|
|
|
snprintf(status, MAX_POLLER_IND_STR_LEN, "Busy (%" PRIu64 ")",
|
|
|
|
g_pollers_info[current_row].busy_count);
|
2020-12-09 09:42:49 +00:00
|
|
|
}
|
2020-03-06 08:52:40 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(6));
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
|
|
|
|
wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(6));
|
|
|
|
} else {
|
|
|
|
wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(8));
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
|
|
|
|
wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(8));
|
|
|
|
}
|
|
|
|
} else {
|
2020-12-09 09:42:49 +00:00
|
|
|
if (g_interval_data == true) {
|
2021-11-22 13:28:20 +00:00
|
|
|
snprintf(status, MAX_POLLER_IND_STR_LEN, "%s", "Idle");
|
2020-12-09 09:42:49 +00:00
|
|
|
} else {
|
2021-11-22 13:28:20 +00:00
|
|
|
snprintf(status, MAX_POLLER_IND_STR_LEN, "Idle (%" PRIu64 ")",
|
|
|
|
g_pollers_info[current_row].busy_count);
|
2020-12-09 09:42:49 +00:00
|
|
|
}
|
2020-12-16 23:53:50 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(7));
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
|
|
|
|
wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(7));
|
2020-12-16 23:53:50 +00:00
|
|
|
} else {
|
2021-11-22 13:28:20 +00:00
|
|
|
wattron(g_tabs[POLLERS_TAB], COLOR_PAIR(9));
|
|
|
|
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_POLLERS_BUSY_COUNT].max_data_string, ALIGN_LEFT, status);
|
|
|
|
wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(9));
|
2020-12-16 23:53:50 +00:00
|
|
|
}
|
2020-04-07 10:44:59 +00:00
|
|
|
}
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 13:07:18 +00:00
|
|
|
static uint8_t
|
|
|
|
refresh_pollers_tab(uint8_t current_page)
|
|
|
|
{
|
2021-07-05 10:59:51 +00:00
|
|
|
uint64_t i, j;
|
2021-11-22 13:28:20 +00:00
|
|
|
uint16_t empty_col = 0;
|
2021-01-20 13:07:18 +00:00
|
|
|
uint8_t max_pages, item_index;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
2021-07-05 10:59:51 +00:00
|
|
|
max_pages = (g_last_pollers_count + g_max_data_rows - 1) / g_max_data_rows;
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
/* Display info */
|
2020-03-09 12:14:43 +00:00
|
|
|
for (i = current_page * g_max_data_rows;
|
2021-07-05 10:59:51 +00:00
|
|
|
i < (uint64_t)((current_page + 1) * g_max_data_rows);
|
2020-03-09 12:14:43 +00:00
|
|
|
i++) {
|
|
|
|
item_index = i - (current_page * g_max_data_rows);
|
|
|
|
|
2021-07-05 10:59:51 +00:00
|
|
|
/* When number of pollers decreases, this will print spaces in places
|
|
|
|
* where non existent pollers were previously displayed. */
|
|
|
|
if (i >= g_last_pollers_count) {
|
|
|
|
for (j = 1; j < (uint64_t)g_max_col - 1; j++) {
|
|
|
|
mvwprintw(g_tabs[POLLERS_TAB], item_index + TABS_DATA_START_ROW, j, " ");
|
|
|
|
}
|
|
|
|
|
2021-07-29 10:31:53 +00:00
|
|
|
empty_col++;
|
2021-07-05 10:59:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
draw_row_background(item_index, POLLERS_TAB);
|
2021-11-22 13:28:20 +00:00
|
|
|
draw_poller_tab_row(i, item_index);
|
2020-04-07 10:44:59 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (item_index == g_selected_row) {
|
|
|
|
wattroff(g_tabs[POLLERS_TAB], COLOR_PAIR(2));
|
2020-04-20 09:14:19 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
}
|
2020-04-20 09:14:19 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
g_max_selected_row = i - current_page * g_max_data_rows - 1 - empty_col;
|
2020-04-20 09:14:19 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
return max_pages;
|
|
|
|
}
|
2020-03-06 09:39:06 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
static void
|
|
|
|
draw_core_tab_row(uint64_t current_row, uint8_t item_index)
|
|
|
|
{
|
|
|
|
struct col_desc *col_desc = g_col_desc[CORES_TAB];
|
|
|
|
uint16_t col = 1;
|
2021-06-17 10:01:39 +00:00
|
|
|
int color_attr = COLOR_PAIR(6);
|
2021-11-22 13:28:20 +00:00
|
|
|
char core[MAX_CORE_STR_LEN], threads_number[MAX_THREAD_COUNT_STR_LEN], cpu_usage[MAX_CPU_STR_LEN],
|
|
|
|
pollers_number[MAX_POLLER_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN],
|
|
|
|
busy_time[MAX_TIME_STR_LEN], core_freq[MAX_CORE_FREQ_STR_LEN],
|
2021-06-17 10:01:39 +00:00
|
|
|
in_interrupt[MAX_INTR_LEN], *status_str;
|
2020-03-06 10:04:49 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
snprintf(threads_number, MAX_THREAD_COUNT_STR_LEN, "%ld",
|
|
|
|
g_cores_info[current_row].threads.threads_count);
|
|
|
|
snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld", g_cores_info[current_row].pollers_count);
|
2020-12-08 09:46:41 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_CORE].disabled) {
|
|
|
|
snprintf(core, MAX_CORE_STR_LEN, "%d", g_cores_info[current_row].lcore);
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_CORE].max_data_string, ALIGN_RIGHT, core);
|
|
|
|
col += col_desc[COL_CORES_CORE].max_data_string + 2;
|
|
|
|
}
|
2021-07-22 11:29:16 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_THREADS].disabled) {
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_CORES_THREADS].name_len / 2), col_desc[COL_CORES_THREADS].max_data_string,
|
|
|
|
ALIGN_LEFT, threads_number);
|
|
|
|
col += col_desc[COL_CORES_THREADS].max_data_string + 2;
|
|
|
|
}
|
2021-07-22 11:29:16 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_POLLERS].disabled) {
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_CORES_POLLERS].name_len / 2), col_desc[COL_CORES_POLLERS].max_data_string,
|
|
|
|
ALIGN_LEFT, pollers_number);
|
|
|
|
col += col_desc[COL_CORES_POLLERS].max_data_string;
|
|
|
|
}
|
|
|
|
|
2022-12-06 05:49:31 +00:00
|
|
|
uint64_t idle_period = g_threads_info[current_row].idle - g_threads_info[current_row].last_idle;
|
|
|
|
uint64_t busy_period = g_threads_info[current_row].busy - g_threads_info[current_row].last_busy;
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_IDLE_TIME].disabled) {
|
|
|
|
if (g_interval_data == true) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_time_str(idle_period, idle_time);
|
2021-11-22 13:28:20 +00:00
|
|
|
} else {
|
|
|
|
get_time_str(g_cores_info[current_row].idle, idle_time);
|
2020-12-08 09:46:41 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_IDLE_TIME].max_data_string, ALIGN_RIGHT, idle_time);
|
|
|
|
col += col_desc[COL_CORES_IDLE_TIME].max_data_string + 2;
|
|
|
|
}
|
2020-12-08 09:46:41 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_BUSY_TIME].disabled) {
|
|
|
|
if (g_interval_data == true) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_time_str(busy_period, busy_time);
|
2021-11-22 13:28:20 +00:00
|
|
|
} else {
|
|
|
|
get_time_str(g_cores_info[current_row].busy, busy_time);
|
2020-04-07 10:44:59 +00:00
|
|
|
}
|
2021-11-22 13:28:20 +00:00
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_BUSY_TIME].max_data_string, ALIGN_RIGHT, busy_time);
|
|
|
|
col += col_desc[COL_CORES_BUSY_TIME].max_data_string + 2;
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
2020-03-09 12:14:43 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_CORE_FREQ].disabled) {
|
|
|
|
if (!g_cores_info[current_row].core_freq) {
|
|
|
|
snprintf(core_freq, MAX_CORE_FREQ_STR_LEN, "%s", "N/A");
|
|
|
|
} else {
|
|
|
|
snprintf(core_freq, MAX_CORE_FREQ_STR_LEN, "%" PRIu32,
|
|
|
|
g_cores_info[current_row].core_freq);
|
|
|
|
}
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_CORE_FREQ].max_data_string, ALIGN_RIGHT, core_freq);
|
|
|
|
col += col_desc[COL_CORES_CORE_FREQ].max_data_string + 2;
|
|
|
|
}
|
2020-04-07 10:44:59 +00:00
|
|
|
|
2021-11-22 13:28:20 +00:00
|
|
|
if (!col_desc[COL_CORES_INTR].disabled) {
|
|
|
|
snprintf(in_interrupt, MAX_INTR_LEN, "%s", g_cores_info[current_row].in_interrupt ? "Yes" : "No");
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index,
|
|
|
|
col + (col_desc[COL_CORES_INTR].name_len / 2), col_desc[COL_CORES_INTR].max_data_string,
|
|
|
|
ALIGN_LEFT, in_interrupt);
|
|
|
|
col += col_desc[COL_CORES_INTR].max_data_string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_CORES_CPU_USAGE].disabled) {
|
2022-12-06 05:49:31 +00:00
|
|
|
get_cpu_usage_str(busy_period, busy_period + idle_period, cpu_usage);
|
2021-11-22 13:28:20 +00:00
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_CPU_USAGE].max_data_string, ALIGN_RIGHT, cpu_usage);
|
2021-06-17 10:01:39 +00:00
|
|
|
col += col_desc[COL_CORES_CPU_USAGE].max_data_string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!col_desc[COL_CORES_STATUS].disabled) {
|
2022-12-06 05:49:31 +00:00
|
|
|
if (busy_period > idle_period) {
|
2021-06-17 10:01:39 +00:00
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
color_attr = COLOR_PAIR(6);
|
|
|
|
} else {
|
|
|
|
color_attr = COLOR_PAIR(8);
|
|
|
|
}
|
|
|
|
status_str = "Busy";
|
|
|
|
} else {
|
|
|
|
if (item_index != g_selected_row) {
|
|
|
|
color_attr = COLOR_PAIR(7);
|
|
|
|
} else {
|
|
|
|
color_attr = COLOR_PAIR(9);
|
|
|
|
}
|
|
|
|
status_str = "Idle";
|
|
|
|
}
|
|
|
|
wattron(g_tabs[CORES_TAB], color_attr);
|
|
|
|
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, col,
|
|
|
|
col_desc[COL_CORES_STATUS].max_data_string, ALIGN_RIGHT, status_str);
|
|
|
|
wattroff(g_tabs[CORES_TAB], color_attr);
|
2021-11-22 13:28:20 +00:00
|
|
|
}
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
static uint8_t
|
|
|
|
refresh_cores_tab(uint8_t current_page)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-11-05 11:12:19 +00:00
|
|
|
uint64_t i;
|
2021-11-22 13:28:20 +00:00
|
|
|
uint16_t count = 0;
|
2020-03-09 12:14:43 +00:00
|
|
|
uint8_t max_pages, item_index;
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
count = g_last_cores_count;
|
2020-03-09 12:14:43 +00:00
|
|
|
|
|
|
|
max_pages = (count + g_max_row - WINDOW_HEADER - 1) / (g_max_row - WINDOW_HEADER);
|
|
|
|
|
|
|
|
for (i = current_page * g_max_data_rows;
|
|
|
|
i < spdk_min(count, (uint64_t)((current_page + 1) * g_max_data_rows));
|
|
|
|
i++) {
|
|
|
|
item_index = i - (current_page * g_max_data_rows);
|
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
draw_row_background(item_index, CORES_TAB);
|
2021-11-22 13:28:20 +00:00
|
|
|
draw_core_tab_row(i, item_index);
|
2020-04-09 08:32:00 +00:00
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
if (item_index == g_selected_row) {
|
|
|
|
wattroff(g_tabs[CORES_TAB], COLOR_PAIR(2));
|
|
|
|
}
|
2020-03-09 12:14:43 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 10:44:59 +00:00
|
|
|
g_max_selected_row = i - current_page * g_max_data_rows - 1;
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
return max_pages;
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
static uint8_t
|
|
|
|
refresh_tab(enum tabs tab, uint8_t current_page)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-03-09 12:14:43 +00:00
|
|
|
uint8_t (*refresh_function[NUMBER_OF_TABS])(uint8_t current_page) = {refresh_threads_tab, refresh_pollers_tab, refresh_cores_tab};
|
2020-02-28 13:00:08 +00:00
|
|
|
int color_pair[NUMBER_OF_TABS] = {COLOR_PAIR(2), COLOR_PAIR(2), COLOR_PAIR(2)};
|
|
|
|
int i;
|
2020-03-09 12:14:43 +00:00
|
|
|
uint8_t max_pages = 0;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
color_pair[tab] = COLOR_PAIR(1);
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
wbkgd(g_tab_win[i], color_pair[i]);
|
|
|
|
}
|
|
|
|
|
2020-03-09 12:14:43 +00:00
|
|
|
max_pages = (*refresh_function[tab])(current_page);
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
2022-01-24 15:43:28 +00:00
|
|
|
wnoutrefresh(g_tab_win[i]);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
2021-01-25 07:32:52 +00:00
|
|
|
draw_menu_win();
|
2020-03-09 12:14:43 +00:00
|
|
|
|
|
|
|
return max_pages;
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
static void
|
|
|
|
print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
|
|
|
{
|
|
|
|
int length, temp;
|
|
|
|
|
|
|
|
length = strlen(string);
|
|
|
|
temp = (width - length) / 2;
|
|
|
|
wattron(win, color);
|
|
|
|
mvwprintw(win, starty, startx + temp, "%s", string);
|
|
|
|
wattroff(win, color);
|
|
|
|
}
|
|
|
|
|
2020-04-07 13:08:09 +00:00
|
|
|
static void
|
2022-04-11 10:24:13 +00:00
|
|
|
print_left(WINDOW *win, int starty, int startx, int width, const char *string, chtype color)
|
2020-04-07 13:08:09 +00:00
|
|
|
{
|
|
|
|
wattron(win, color);
|
|
|
|
mvwprintw(win, starty, startx, "%s", string);
|
|
|
|
wattroff(win, color);
|
|
|
|
}
|
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
static void
|
|
|
|
apply_filters(enum tabs tab)
|
|
|
|
{
|
|
|
|
wclear(g_tabs[tab]);
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
|
2020-04-20 09:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ITEM **
|
|
|
|
draw_filtering_menu(uint8_t position, WINDOW *filter_win, uint8_t tab, MENU **my_menu)
|
|
|
|
{
|
|
|
|
const int ADDITIONAL_ELEMENTS = 3;
|
|
|
|
const int ROW_PADDING = 6;
|
|
|
|
const int WINDOW_START_X = 1;
|
|
|
|
const int WINDOW_START_Y = 3;
|
|
|
|
const int WINDOW_COLUMNS = 2;
|
|
|
|
struct col_desc *col_desc = g_col_desc[tab];
|
|
|
|
ITEM **my_items;
|
|
|
|
MENU *menu;
|
|
|
|
int i, elements;
|
|
|
|
uint8_t len = 0;
|
|
|
|
|
|
|
|
for (i = 0; col_desc[i].name != NULL; ++i) {
|
|
|
|
len = spdk_max(col_desc[i].name_len, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
elements = i;
|
|
|
|
|
|
|
|
my_items = (ITEM **)calloc(elements * WINDOW_COLUMNS + ADDITIONAL_ELEMENTS, sizeof(ITEM *));
|
2020-04-24 17:47:24 +00:00
|
|
|
if (my_items == NULL) {
|
|
|
|
fprintf(stderr, "Unable to allocate an item list in draw_filtering_menu.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-04-20 09:14:19 +00:00
|
|
|
|
|
|
|
for (i = 0; i < elements * 2; i++) {
|
|
|
|
my_items[i] = new_item(col_desc[i / WINDOW_COLUMNS].name, NULL);
|
|
|
|
i++;
|
|
|
|
my_items[i] = new_item(col_desc[i / WINDOW_COLUMNS].disabled ? "[ ]" : "[*]", NULL);
|
|
|
|
}
|
|
|
|
|
2020-03-05 07:57:27 +00:00
|
|
|
my_items[i] = new_item(" CLOSE", NULL);
|
2020-04-20 09:14:19 +00:00
|
|
|
set_item_userptr(my_items[i], apply_filters);
|
|
|
|
|
|
|
|
menu = new_menu((ITEM **)my_items);
|
|
|
|
|
|
|
|
menu_opts_off(menu, O_SHOWDESC);
|
|
|
|
set_menu_format(menu, elements + 1, WINDOW_COLUMNS);
|
|
|
|
|
|
|
|
set_menu_win(menu, filter_win);
|
|
|
|
set_menu_sub(menu, derwin(filter_win, elements + 1, len + ROW_PADDING, WINDOW_START_Y,
|
|
|
|
WINDOW_START_X));
|
|
|
|
|
|
|
|
*my_menu = menu;
|
|
|
|
|
|
|
|
post_menu(menu);
|
|
|
|
refresh();
|
|
|
|
wrefresh(filter_win);
|
|
|
|
|
|
|
|
for (i = 0; i < position / WINDOW_COLUMNS; i++) {
|
|
|
|
menu_driver(menu, REQ_DOWN_ITEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
return my_items;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
delete_filtering_menu(MENU *my_menu, ITEM **my_items, uint8_t elements)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
unpost_menu(my_menu);
|
|
|
|
free_menu(my_menu);
|
|
|
|
for (i = 0; i < elements * 2 + 2; ++i) {
|
|
|
|
free_item(my_items[i]);
|
|
|
|
}
|
|
|
|
free(my_items);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ITEM **
|
|
|
|
refresh_filtering_menu(MENU **my_menu, WINDOW *filter_win, uint8_t tab, ITEM **my_items,
|
|
|
|
uint8_t elements, uint8_t position)
|
|
|
|
{
|
|
|
|
delete_filtering_menu(*my_menu, my_items, elements);
|
|
|
|
return draw_filtering_menu(position, filter_win, tab, my_menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
filter_columns(uint8_t tab)
|
|
|
|
{
|
|
|
|
const int WINDOW_HEADER_LEN = 5;
|
|
|
|
const int WINDOW_BORDER_LEN = 8;
|
|
|
|
const int WINDOW_HEADER_END_LINE = 2;
|
|
|
|
const int WINDOW_COLUMNS = 2;
|
|
|
|
struct col_desc *col_desc = g_col_desc[tab];
|
|
|
|
PANEL *filter_panel;
|
|
|
|
WINDOW *filter_win;
|
|
|
|
ITEM **my_items;
|
2020-04-24 17:47:24 +00:00
|
|
|
MENU *my_menu = NULL;
|
2020-04-20 09:14:19 +00:00
|
|
|
int i, c, elements;
|
|
|
|
bool stop_loop = false;
|
|
|
|
ITEM *cur;
|
|
|
|
void (*p)(enum tabs tab);
|
|
|
|
uint8_t current_index, len = 0;
|
2021-03-16 02:02:06 +00:00
|
|
|
bool disabled[TABS_COL_COUNT];
|
2020-04-20 09:14:19 +00:00
|
|
|
|
|
|
|
for (i = 0; col_desc[i].name != NULL; ++i) {
|
|
|
|
len = spdk_max(col_desc[i].name_len, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
elements = i;
|
|
|
|
|
|
|
|
filter_win = newwin(elements + WINDOW_HEADER_LEN, len + WINDOW_BORDER_LEN,
|
|
|
|
(g_max_row - elements - 1) / 2, (g_max_col - len) / 2);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(filter_win != NULL);
|
2020-04-20 09:14:19 +00:00
|
|
|
keypad(filter_win, TRUE);
|
|
|
|
filter_panel = new_panel(filter_win);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(filter_panel != NULL);
|
2020-04-20 09:14:19 +00:00
|
|
|
|
|
|
|
top_panel(filter_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
|
|
|
|
box(filter_win, 0, 0);
|
|
|
|
|
|
|
|
print_in_middle(filter_win, 1, 0, len + WINDOW_BORDER_LEN, "Filtering", COLOR_PAIR(3));
|
|
|
|
mvwaddch(filter_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
|
|
|
|
mvwhline(filter_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, len + WINDOW_BORDER_LEN - 2);
|
|
|
|
mvwaddch(filter_win, WINDOW_HEADER_END_LINE, len + WINDOW_BORDER_LEN - 1, ACS_RTEE);
|
|
|
|
|
|
|
|
my_items = draw_filtering_menu(0, filter_win, tab, &my_menu);
|
2020-04-27 16:31:53 +00:00
|
|
|
if (my_items == NULL || my_menu == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2020-04-20 09:14:19 +00:00
|
|
|
|
2021-03-16 02:02:06 +00:00
|
|
|
for (int i = 0; i < TABS_COL_COUNT; i++) {
|
|
|
|
disabled[i] = col_desc[i].disabled;
|
|
|
|
}
|
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
while (!stop_loop) {
|
|
|
|
c = wgetch(filter_win);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case KEY_DOWN:
|
|
|
|
menu_driver(my_menu, REQ_DOWN_ITEM);
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
menu_driver(my_menu, REQ_UP_ITEM);
|
|
|
|
break;
|
|
|
|
case 27: /* ESC */
|
|
|
|
case 'q':
|
2021-03-16 02:02:06 +00:00
|
|
|
for (int i = 0; i < TABS_COL_COUNT; i++) {
|
|
|
|
cur = current_item(my_menu);
|
|
|
|
col_desc[i].disabled = disabled[i];
|
|
|
|
|
|
|
|
my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
|
|
|
|
item_index(cur) + 1);
|
|
|
|
if (my_items == NULL || my_menu == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
case ' ': /* Space */
|
|
|
|
cur = current_item(my_menu);
|
|
|
|
current_index = item_index(cur) / WINDOW_COLUMNS;
|
|
|
|
col_desc[current_index].disabled = !col_desc[current_index].disabled;
|
|
|
|
my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
|
|
|
|
item_index(cur) + 1);
|
2020-04-27 16:31:53 +00:00
|
|
|
if (my_items == NULL || my_menu == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2020-04-20 09:14:19 +00:00
|
|
|
break;
|
|
|
|
case 10: /* Enter */
|
|
|
|
cur = current_item(my_menu);
|
|
|
|
current_index = item_index(cur) / WINDOW_COLUMNS;
|
|
|
|
if (current_index == elements) {
|
|
|
|
stop_loop = true;
|
|
|
|
p = item_userptr(cur);
|
|
|
|
p(tab);
|
|
|
|
} else {
|
|
|
|
col_desc[current_index].disabled = !col_desc[current_index].disabled;
|
|
|
|
my_items = refresh_filtering_menu(&my_menu, filter_win, tab, my_items, elements,
|
|
|
|
item_index(cur) + 1);
|
2020-04-27 16:31:53 +00:00
|
|
|
if (my_items == NULL || my_menu == NULL) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2020-04-20 09:14:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wrefresh(filter_win);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete_filtering_menu(my_menu, my_items, elements);
|
|
|
|
|
|
|
|
del_panel(filter_panel);
|
|
|
|
delwin(filter_win);
|
|
|
|
|
|
|
|
wclear(g_menu_win);
|
|
|
|
draw_menu_win();
|
2020-04-27 16:31:53 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
fprintf(stderr, "Unable to filter the columns due to allocation failure.\n");
|
|
|
|
assert(false);
|
2020-04-20 09:14:19 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
static void
|
|
|
|
sort_type(enum tabs tab, int item_index)
|
|
|
|
{
|
|
|
|
g_current_sort_col[tab] = item_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-10-13 16:21:58 +00:00
|
|
|
sort_type2(enum tabs tab, int item_index)
|
|
|
|
{
|
|
|
|
g_current_sort_col2[tab] = item_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
change_sorting(uint8_t tab, int winnum, bool *pstop_loop)
|
2020-03-27 09:13:14 +00:00
|
|
|
{
|
|
|
|
const int WINDOW_HEADER_LEN = 4;
|
|
|
|
const int WINDOW_BORDER_LEN = 3;
|
|
|
|
const int WINDOW_START_X = 1;
|
2021-10-13 16:21:58 +00:00
|
|
|
const int WINDOW_START_Y = 4;
|
|
|
|
const int WINDOW_HEADER_END_LINE = 3;
|
|
|
|
const int WINDOW_MIN_WIDTH = 31;
|
2020-03-27 09:13:14 +00:00
|
|
|
PANEL *sort_panel;
|
|
|
|
WINDOW *sort_win;
|
|
|
|
ITEM **my_items;
|
|
|
|
MENU *my_menu;
|
|
|
|
int i, c, elements;
|
|
|
|
bool stop_loop = false;
|
|
|
|
ITEM *cur;
|
2021-10-13 16:21:58 +00:00
|
|
|
char *name;
|
|
|
|
char *help;
|
2020-03-27 09:13:14 +00:00
|
|
|
void (*p)(enum tabs tab, int item_index);
|
2021-10-13 16:21:58 +00:00
|
|
|
uint8_t len = WINDOW_MIN_WIDTH;
|
2020-03-27 09:13:14 +00:00
|
|
|
|
2020-04-20 09:14:19 +00:00
|
|
|
for (i = 0; g_col_desc[tab][i].name != NULL; ++i) {
|
|
|
|
len = spdk_max(len, g_col_desc[tab][i].name_len);
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
elements = i;
|
|
|
|
|
|
|
|
my_items = (ITEM **)calloc(elements + 1, sizeof(ITEM *));
|
2020-04-24 17:47:24 +00:00
|
|
|
if (my_items == NULL) {
|
|
|
|
fprintf(stderr, "Unable to allocate an item list in change_sorting.\n");
|
|
|
|
return;
|
|
|
|
}
|
2020-03-27 09:13:14 +00:00
|
|
|
|
|
|
|
for (i = 0; i < elements; ++i) {
|
2020-04-20 09:14:19 +00:00
|
|
|
my_items[i] = new_item(g_col_desc[tab][i].name, NULL);
|
2021-10-13 16:21:58 +00:00
|
|
|
set_item_userptr(my_items[i], (winnum == 0) ? sort_type : sort_type2);
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
my_menu = new_menu((ITEM **)my_items);
|
|
|
|
|
|
|
|
menu_opts_off(my_menu, O_SHOWDESC);
|
|
|
|
|
2021-10-13 16:21:58 +00:00
|
|
|
sort_win = newwin(elements + WINDOW_HEADER_LEN + 1, len + WINDOW_BORDER_LEN,
|
|
|
|
(g_max_row - elements) / 2,
|
|
|
|
(g_max_col - len) / 2 - len + len * winnum);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(sort_win != NULL);
|
2020-03-27 09:13:14 +00:00
|
|
|
keypad(sort_win, TRUE);
|
|
|
|
sort_panel = new_panel(sort_win);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(sort_panel != NULL);
|
2020-03-27 09:13:14 +00:00
|
|
|
|
|
|
|
top_panel(sort_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
|
|
|
|
set_menu_win(my_menu, sort_win);
|
|
|
|
set_menu_sub(my_menu, derwin(sort_win, elements, len + 1, WINDOW_START_Y, WINDOW_START_X));
|
|
|
|
box(sort_win, 0, 0);
|
|
|
|
|
2021-10-13 16:21:58 +00:00
|
|
|
if (winnum == 0) {
|
|
|
|
name = "Sorting #1";
|
|
|
|
help = "Right key for second sorting";
|
|
|
|
} else {
|
|
|
|
name = "Sorting #2";
|
|
|
|
help = "Left key for first sorting";
|
|
|
|
}
|
|
|
|
|
|
|
|
print_in_middle(sort_win, 1, 0, len + WINDOW_BORDER_LEN, name, COLOR_PAIR(3));
|
|
|
|
print_in_middle(sort_win, 2, 0, len + WINDOW_BORDER_LEN, help, COLOR_PAIR(3));
|
2020-03-27 09:13:14 +00:00
|
|
|
mvwaddch(sort_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
|
|
|
|
mvwhline(sort_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, len + 1);
|
|
|
|
mvwaddch(sort_win, WINDOW_HEADER_END_LINE, len + WINDOW_BORDER_LEN - 1, ACS_RTEE);
|
|
|
|
|
|
|
|
post_menu(my_menu);
|
|
|
|
refresh();
|
|
|
|
wrefresh(sort_win);
|
|
|
|
|
|
|
|
while (!stop_loop) {
|
|
|
|
c = wgetch(sort_win);
|
2021-10-13 16:21:58 +00:00
|
|
|
/*
|
|
|
|
* First sorting window:
|
|
|
|
* Up/Down - select first sorting column;
|
|
|
|
* Enter - apply current column;
|
|
|
|
* Right - open second sorting window.
|
|
|
|
* Second sorting window:
|
|
|
|
* Up/Down - select second sorting column;
|
|
|
|
* Enter - apply current column of both sorting windows;
|
|
|
|
* Left - exit second window and reset second sorting key;
|
|
|
|
* Right - do nothing.
|
|
|
|
*/
|
2020-03-27 09:13:14 +00:00
|
|
|
switch (c) {
|
|
|
|
case KEY_DOWN:
|
|
|
|
menu_driver(my_menu, REQ_DOWN_ITEM);
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
menu_driver(my_menu, REQ_UP_ITEM);
|
|
|
|
break;
|
2021-10-13 16:21:58 +00:00
|
|
|
case KEY_RIGHT:
|
|
|
|
if (winnum > 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
change_sorting(tab, winnum + 1, &stop_loop);
|
|
|
|
/* Restore input. */
|
|
|
|
keypad(sort_win, TRUE);
|
|
|
|
post_menu(my_menu);
|
|
|
|
refresh();
|
|
|
|
wrefresh(sort_win);
|
|
|
|
redrawwin(sort_win);
|
|
|
|
if (winnum == 0) {
|
|
|
|
cur = current_item(my_menu);
|
|
|
|
p = item_userptr(cur);
|
|
|
|
p(tab, item_index(cur));
|
|
|
|
}
|
|
|
|
break;
|
2020-03-27 09:13:14 +00:00
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
2021-10-13 16:21:58 +00:00
|
|
|
case KEY_LEFT:
|
|
|
|
if (winnum > 0) {
|
|
|
|
sort_type2(tab, COL_THREADS_NONE);
|
|
|
|
}
|
|
|
|
/* FALLTHROUGH */
|
2020-03-27 09:13:14 +00:00
|
|
|
case 10: /* Enter */
|
|
|
|
stop_loop = true;
|
2021-10-13 16:21:58 +00:00
|
|
|
if (winnum > 0 && c == 10) {
|
|
|
|
*pstop_loop = true;
|
|
|
|
}
|
|
|
|
if (c == 10) {
|
|
|
|
cur = current_item(my_menu);
|
|
|
|
p = item_userptr(cur);
|
|
|
|
p(tab, item_index(cur));
|
|
|
|
}
|
2020-03-27 09:13:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
wrefresh(sort_win);
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:21:58 +00:00
|
|
|
if (winnum == 0) {
|
|
|
|
wclear(g_tabs[tab]);
|
|
|
|
draw_tabs(tab, g_current_sort_col[tab], g_current_sort_col2[tab]);
|
|
|
|
}
|
|
|
|
|
2020-03-27 09:13:14 +00:00
|
|
|
unpost_menu(my_menu);
|
|
|
|
free_menu(my_menu);
|
|
|
|
|
|
|
|
for (i = 0; i < elements; ++i) {
|
|
|
|
free_item(my_items[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(my_items);
|
|
|
|
|
|
|
|
del_panel(sort_panel);
|
|
|
|
delwin(sort_win);
|
|
|
|
|
2021-10-13 16:21:58 +00:00
|
|
|
if (winnum == 0) {
|
|
|
|
wclear(g_menu_win);
|
|
|
|
draw_menu_win();
|
|
|
|
}
|
2020-03-27 09:13:14 +00:00
|
|
|
}
|
|
|
|
|
2021-04-14 08:25:46 +00:00
|
|
|
static int
|
2021-04-19 12:03:16 +00:00
|
|
|
check_resize_interface(uint8_t active_tab, uint8_t *current_page)
|
|
|
|
{
|
|
|
|
int max_row, max_col;
|
|
|
|
uint16_t required_size = WINDOW_HEADER + 1;
|
|
|
|
|
|
|
|
/* Check if interface has to be resized (terminal size changed) */
|
|
|
|
getmaxyx(stdscr, max_row, max_col);
|
|
|
|
|
|
|
|
if (max_row != g_max_row || max_col != g_max_col) {
|
|
|
|
if (max_row != g_max_row) {
|
|
|
|
*current_page = 0;
|
|
|
|
}
|
|
|
|
g_max_row = spdk_max(max_row, required_size);
|
|
|
|
g_max_col = max_col;
|
|
|
|
g_data_win_size = g_max_row - required_size + 1;
|
|
|
|
g_max_data_rows = g_max_row - WINDOW_HEADER;
|
|
|
|
resize_interface(active_tab);
|
2021-04-14 08:25:46 +00:00
|
|
|
|
|
|
|
return 1;
|
2021-04-19 12:03:16 +00:00
|
|
|
}
|
2021-04-14 08:25:46 +00:00
|
|
|
|
|
|
|
return 0;
|
2021-04-19 12:03:16 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 05:32:35 +00:00
|
|
|
static void
|
|
|
|
change_refresh_rate(void)
|
|
|
|
{
|
|
|
|
const int WINDOW_HEADER_END_LINE = 2;
|
|
|
|
PANEL *refresh_panel;
|
|
|
|
WINDOW *refresh_win;
|
|
|
|
int c;
|
|
|
|
bool stop_loop = false;
|
|
|
|
uint32_t rr_tmp, refresh_rate = 0;
|
|
|
|
char refresh_rate_str[MAX_STRING_LEN];
|
|
|
|
|
|
|
|
refresh_win = newwin(RR_WIN_HEIGHT, RR_WIN_WIDTH, (g_max_row - RR_WIN_HEIGHT - 1) / 2,
|
|
|
|
(g_max_col - RR_WIN_WIDTH) / 2);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(refresh_win != NULL);
|
2020-04-10 05:32:35 +00:00
|
|
|
keypad(refresh_win, TRUE);
|
|
|
|
refresh_panel = new_panel(refresh_win);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(refresh_panel != NULL);
|
2020-04-10 05:32:35 +00:00
|
|
|
|
|
|
|
top_panel(refresh_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
|
|
|
|
box(refresh_win, 0, 0);
|
|
|
|
|
|
|
|
print_in_middle(refresh_win, 1, 0, RR_WIN_WIDTH + 1, "Enter refresh rate value [s]", COLOR_PAIR(3));
|
|
|
|
mvwaddch(refresh_win, WINDOW_HEADER_END_LINE, 0, ACS_LTEE);
|
|
|
|
mvwhline(refresh_win, WINDOW_HEADER_END_LINE, 1, ACS_HLINE, RR_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(refresh_win, WINDOW_HEADER_END_LINE, RR_WIN_WIDTH, ACS_RTEE);
|
|
|
|
mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1, (RR_WIN_WIDTH - 1) / 2, "%d", refresh_rate);
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
wrefresh(refresh_win);
|
|
|
|
|
|
|
|
while (!stop_loop) {
|
|
|
|
c = wgetch(refresh_win);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
rr_tmp = refresh_rate * 10 + c - '0';
|
|
|
|
|
|
|
|
if (rr_tmp <= RR_MAX_VALUE) {
|
|
|
|
refresh_rate = rr_tmp;
|
|
|
|
snprintf(refresh_rate_str, MAX_STRING_LEN - 1, "%d", refresh_rate);
|
|
|
|
mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
|
|
|
|
(RR_WIN_WIDTH - 1 - strlen(refresh_rate_str)) / 2, "%d", refresh_rate);
|
|
|
|
refresh();
|
|
|
|
wrefresh(refresh_win);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_BACKSPACE:
|
|
|
|
case 127:
|
|
|
|
case '\b':
|
|
|
|
refresh_rate = refresh_rate / 10;
|
|
|
|
snprintf(refresh_rate_str, MAX_STRING_LEN - 1, "%d", refresh_rate);
|
|
|
|
mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
|
|
|
|
(RR_WIN_WIDTH - 1 - strlen(refresh_rate_str) - 2) / 2, " ");
|
|
|
|
mvwprintw(refresh_win, WINDOW_HEADER_END_LINE + 1,
|
|
|
|
(RR_WIN_WIDTH - 1 - strlen(refresh_rate_str)) / 2, "%d", refresh_rate);
|
|
|
|
refresh();
|
|
|
|
wrefresh(refresh_win);
|
|
|
|
break;
|
|
|
|
case 27: /* ESC */
|
|
|
|
case 'q':
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
case 10: /* Enter */
|
2021-04-14 06:48:19 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2020-04-10 05:32:35 +00:00
|
|
|
g_sleep_time = refresh_rate;
|
2021-04-14 06:48:19 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-04-10 05:32:35 +00:00
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wrefresh(refresh_win);
|
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(refresh_panel);
|
|
|
|
delwin(refresh_win);
|
|
|
|
}
|
|
|
|
|
2020-04-09 08:32:00 +00:00
|
|
|
static void
|
2021-04-14 14:08:50 +00:00
|
|
|
free_poller_history(void)
|
2020-04-09 08:32:00 +00:00
|
|
|
{
|
|
|
|
struct run_counter_history *history, *tmp;
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(history, &g_run_counter_history, link, tmp) {
|
|
|
|
TAILQ_REMOVE(&g_run_counter_history, history, link);
|
|
|
|
free(history);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-01 10:51:20 +00:00
|
|
|
static uint64_t
|
|
|
|
get_position_for_window(uint64_t window_size, uint64_t max_size)
|
|
|
|
{
|
|
|
|
/* This function calculates position for pop-up detail window.
|
|
|
|
* Since horizontal and vertical positions are calculated the same way
|
|
|
|
* there is no need for separate functions. */
|
|
|
|
window_size = spdk_min(window_size, max_size);
|
|
|
|
|
|
|
|
return (max_size - window_size) / 2;
|
|
|
|
}
|
|
|
|
|
2021-05-21 13:42:25 +00:00
|
|
|
static void
|
2021-10-27 05:36:43 +00:00
|
|
|
print_bottom_message(char *msg)
|
2021-05-21 13:42:25 +00:00
|
|
|
{
|
2021-10-27 05:36:43 +00:00
|
|
|
uint64_t i;
|
|
|
|
|
|
|
|
for (i = 1; i < (uint64_t)g_max_col - 1; i++) {
|
|
|
|
mvprintw(g_max_row - 1, i, " ");
|
|
|
|
}
|
2021-11-19 08:07:31 +00:00
|
|
|
mvprintw(g_max_row - 1, g_max_col - strlen(msg) - 2, "%s", msg);
|
2021-05-21 13:42:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 13:08:09 +00:00
|
|
|
static void
|
2021-12-20 16:29:14 +00:00
|
|
|
draw_thread_win_content(WINDOW *thread_win, struct rpc_thread_info *thread_info)
|
2020-04-07 13:08:09 +00:00
|
|
|
{
|
2021-12-20 16:29:14 +00:00
|
|
|
uint64_t current_row, i, time;
|
2021-06-22 11:44:20 +00:00
|
|
|
char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];
|
2020-04-07 13:08:09 +00:00
|
|
|
|
|
|
|
box(thread_win, 0, 0);
|
|
|
|
|
2021-12-20 16:29:14 +00:00
|
|
|
print_in_middle(thread_win, 1, 0, THREAD_WIN_WIDTH, thread_info->name,
|
2020-04-07 13:08:09 +00:00
|
|
|
COLOR_PAIR(3));
|
|
|
|
mvwhline(thread_win, 2, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(thread_win, 2, THREAD_WIN_WIDTH, ACS_RTEE);
|
|
|
|
|
|
|
|
print_left(thread_win, 3, THREAD_WIN_FIRST_COL, THREAD_WIN_WIDTH,
|
|
|
|
"Core: Idle [us]: Busy [us]:", COLOR_PAIR(5));
|
2021-11-23 22:48:22 +00:00
|
|
|
mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 6, "%d",
|
2021-12-20 16:29:14 +00:00
|
|
|
thread_info->core_num);
|
2020-12-09 09:42:49 +00:00
|
|
|
|
|
|
|
if (g_interval_data) {
|
2021-12-20 16:29:14 +00:00
|
|
|
get_time_str(thread_info->idle - thread_info->last_idle, idle_time);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 32, "%s", idle_time);
|
2021-12-20 16:29:14 +00:00
|
|
|
get_time_str(thread_info->busy - thread_info->last_busy, busy_time);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 54, "%s", busy_time);
|
2020-12-09 09:42:49 +00:00
|
|
|
} else {
|
2021-12-20 16:29:14 +00:00
|
|
|
get_time_str(thread_info->idle, idle_time);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 32, "%s", idle_time);
|
2021-12-20 16:29:14 +00:00
|
|
|
get_time_str(thread_info->busy, busy_time);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(thread_win, 3, THREAD_WIN_FIRST_COL + 54, "%s", busy_time);
|
2020-12-09 09:42:49 +00:00
|
|
|
}
|
2020-04-07 13:08:09 +00:00
|
|
|
|
|
|
|
print_left(thread_win, 4, THREAD_WIN_FIRST_COL, THREAD_WIN_WIDTH,
|
|
|
|
"Active pollers: Timed pollers: Paused pollers:", COLOR_PAIR(5));
|
|
|
|
mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 17, "%" PRIu64,
|
2021-12-20 16:29:14 +00:00
|
|
|
thread_info->active_pollers_count);
|
2020-04-07 13:08:09 +00:00
|
|
|
mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 36, "%" PRIu64,
|
2021-12-20 16:29:14 +00:00
|
|
|
thread_info->timed_pollers_count);
|
2020-04-07 13:08:09 +00:00
|
|
|
mvwprintw(thread_win, 4, THREAD_WIN_FIRST_COL + 59, "%" PRIu64,
|
2021-12-20 16:29:14 +00:00
|
|
|
thread_info->paused_pollers_count);
|
2020-04-07 13:08:09 +00:00
|
|
|
|
|
|
|
mvwhline(thread_win, 5, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
|
|
|
|
|
|
|
|
print_in_middle(thread_win, 6, 0, THREAD_WIN_WIDTH,
|
|
|
|
"Pollers Type Total run count Period", COLOR_PAIR(5));
|
|
|
|
|
|
|
|
mvwhline(thread_win, 7, 1, ACS_HLINE, THREAD_WIN_WIDTH - 2);
|
|
|
|
|
|
|
|
current_row = 8;
|
|
|
|
|
2021-06-22 11:44:20 +00:00
|
|
|
for (i = 0; i < g_last_pollers_count; i++) {
|
2021-12-20 16:29:14 +00:00
|
|
|
if (g_pollers_info[i].thread_id == thread_info->id) {
|
2021-06-22 11:44:20 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL, "%s", g_pollers_info[i].name);
|
|
|
|
if (g_pollers_info[i].type == SPDK_ACTIVE_POLLER) {
|
2020-04-07 13:08:09 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Active");
|
2021-06-22 11:44:20 +00:00
|
|
|
} else if (g_pollers_info[i].type == SPDK_TIMED_POLLER) {
|
2020-04-07 13:08:09 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Timed");
|
2021-06-22 11:44:20 +00:00
|
|
|
} else {
|
2020-04-07 13:08:09 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 33, "Paused");
|
|
|
|
}
|
2021-06-22 11:44:20 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 41, "%" PRIu64,
|
|
|
|
g_pollers_info[i].run_count);
|
|
|
|
if (g_pollers_info[i].period_ticks) {
|
2021-06-28 11:27:00 +00:00
|
|
|
time = g_pollers_info[i].period_ticks * SPDK_SEC_TO_USEC / g_tick_rate;
|
2021-06-22 11:44:20 +00:00
|
|
|
mvwprintw(thread_win, current_row, THREAD_WIN_FIRST_COL + 59, "%" PRIu64, time);
|
|
|
|
}
|
|
|
|
current_row++;
|
2020-04-07 13:08:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-24 15:43:28 +00:00
|
|
|
wnoutrefresh(thread_win);
|
2021-12-20 16:29:14 +00:00
|
|
|
}
|
|
|
|
|
2022-01-25 09:21:27 +00:00
|
|
|
static int
|
|
|
|
get_single_thread_info(uint64_t thread_id, struct rpc_thread_info *thread_info)
|
|
|
|
{
|
|
|
|
uint64_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < g_last_threads_count; i++) {
|
|
|
|
if (g_threads_info[i].id == thread_id) {
|
|
|
|
memcpy(thread_info, &g_threads_info[i], sizeof(struct rpc_thread_info));
|
2022-08-22 10:16:50 +00:00
|
|
|
thread_info->name = strdup(g_threads_info[i].name);
|
|
|
|
thread_info->cpumask = strdup(g_threads_info[i].cpumask);
|
|
|
|
|
|
|
|
if (thread_info->name == NULL || thread_info->cpumask == NULL) {
|
|
|
|
print_bottom_message("Unable to allocate memory for thread name and cpumask. Exiting pop-up.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-01-25 09:21:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
print_bottom_message("Selected thread no longer exists. Exiting pop-up.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-01-25 10:01:42 +00:00
|
|
|
static void
|
|
|
|
draw_core_win_content(WINDOW *core_win, struct rpc_core_info *core_info)
|
|
|
|
{
|
|
|
|
uint64_t i;
|
|
|
|
char core_win_title[25];
|
|
|
|
char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];
|
|
|
|
|
|
|
|
box(core_win, 0, 0);
|
|
|
|
snprintf(core_win_title, sizeof(core_win_title), "Core %" PRIu32 " details",
|
|
|
|
core_info->lcore);
|
|
|
|
print_in_middle(core_win, 1, 0, CORE_WIN_WIDTH, core_win_title, COLOR_PAIR(3));
|
|
|
|
|
|
|
|
mvwaddch(core_win, -1, 0, ACS_LTEE);
|
|
|
|
mvwhline(core_win, 2, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(core_win, 2, CORE_WIN_WIDTH, ACS_RTEE);
|
|
|
|
print_left(core_win, 3, 1, CORE_WIN_WIDTH - (CORE_WIN_WIDTH / 3),
|
|
|
|
"Frequency: Intr:", COLOR_PAIR(5));
|
|
|
|
if (core_info->core_freq) {
|
|
|
|
mvwprintw(core_win, 3, CORE_WIN_FIRST_COL - 3, "%" PRIu32,
|
|
|
|
core_info->core_freq);
|
|
|
|
} else {
|
|
|
|
mvwprintw(core_win, 3, CORE_WIN_FIRST_COL - 3, "%s", "N/A");
|
|
|
|
}
|
|
|
|
|
|
|
|
mvwprintw(core_win, 3, CORE_WIN_FIRST_COL + 15, "%s",
|
|
|
|
core_info->in_interrupt ? "Yes" : "No");
|
|
|
|
|
|
|
|
mvwaddch(core_win, -1, 0, ACS_LTEE);
|
|
|
|
mvwhline(core_win, 4, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(core_win, 4, CORE_WIN_WIDTH, ACS_RTEE);
|
|
|
|
print_left(core_win, 5, 1, CORE_WIN_WIDTH, "Thread count: Idle time:", COLOR_PAIR(5));
|
|
|
|
|
|
|
|
mvwprintw(core_win, 5, CORE_WIN_FIRST_COL, "%" PRIu64,
|
|
|
|
core_info->threads.threads_count);
|
|
|
|
|
|
|
|
if (g_interval_data == true) {
|
|
|
|
get_time_str(core_info->idle - core_info->last_idle, idle_time);
|
|
|
|
get_time_str(core_info->busy - core_info->last_busy, busy_time);
|
|
|
|
} else {
|
|
|
|
get_time_str(core_info->idle, idle_time);
|
|
|
|
get_time_str(core_info->busy, busy_time);
|
|
|
|
}
|
|
|
|
mvwprintw(core_win, 5, CORE_WIN_FIRST_COL + 20, "%s", idle_time);
|
|
|
|
mvwhline(core_win, 6, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
|
|
|
|
|
|
|
|
print_left(core_win, 7, 1, CORE_WIN_WIDTH, "Poller count: Busy time:", COLOR_PAIR(5));
|
|
|
|
mvwprintw(core_win, 7, CORE_WIN_FIRST_COL, "%" PRIu64,
|
|
|
|
core_info->pollers_count);
|
|
|
|
|
|
|
|
mvwprintw(core_win, 7, CORE_WIN_FIRST_COL + 20, "%s", busy_time);
|
|
|
|
|
|
|
|
mvwhline(core_win, 8, 1, ACS_HLINE, CORE_WIN_WIDTH - 2);
|
|
|
|
print_left(core_win, 9, 1, CORE_WIN_WIDTH, "Threads on this core", COLOR_PAIR(5));
|
|
|
|
|
|
|
|
for (i = 0; i < core_info->threads.threads_count; i++) {
|
|
|
|
mvwprintw(core_win, i + 10, 1, "%s", core_info->threads.thread[i].name);
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
|
|
|
|
wnoutrefresh(core_win);
|
|
|
|
}
|
|
|
|
|
2021-12-20 16:29:14 +00:00
|
|
|
static void
|
2022-01-24 16:27:54 +00:00
|
|
|
display_thread(uint64_t thread_id, uint8_t current_page, uint8_t active_tab,
|
|
|
|
WINDOW *core_popup, struct rpc_core_info *core_info)
|
2021-12-20 16:29:14 +00:00
|
|
|
{
|
2021-07-26 13:00:30 +00:00
|
|
|
PANEL *thread_panel = NULL;
|
|
|
|
WINDOW *thread_win = NULL;
|
2021-12-20 16:29:14 +00:00
|
|
|
struct rpc_thread_info thread_info;
|
2021-04-14 08:25:46 +00:00
|
|
|
uint64_t pollers_count, threads_count, last_pollers_count = 0;
|
2021-12-20 16:29:14 +00:00
|
|
|
int c;
|
|
|
|
bool stop_loop = false;
|
2021-07-26 13:00:30 +00:00
|
|
|
long int time_last, time_dif;
|
|
|
|
struct timespec time_now;
|
2021-12-20 16:29:14 +00:00
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_last = time_now.tv_sec;
|
2021-12-20 16:29:14 +00:00
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
memset(&thread_info, 0, sizeof(thread_info));
|
2021-12-20 16:29:14 +00:00
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
while (!stop_loop) {
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
if (get_single_thread_info(thread_id, &thread_info)) {
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2022-08-22 10:16:50 +00:00
|
|
|
free(thread_info.name);
|
|
|
|
free(thread_info.cpumask);
|
|
|
|
thread_info.name = NULL;
|
|
|
|
thread_info.cpumask = NULL;
|
2021-07-26 13:00:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pollers_count = thread_info.active_pollers_count +
|
|
|
|
thread_info.timed_pollers_count +
|
|
|
|
thread_info.paused_pollers_count;
|
|
|
|
if (pollers_count != last_pollers_count) {
|
|
|
|
if (thread_win != NULL) {
|
|
|
|
assert(thread_panel != NULL);
|
|
|
|
del_panel(thread_panel);
|
|
|
|
delwin(thread_win);
|
|
|
|
}
|
2021-12-20 16:29:14 +00:00
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
thread_win = newwin(pollers_count + THREAD_WIN_HEIGHT, THREAD_WIN_WIDTH,
|
|
|
|
get_position_for_window(THREAD_WIN_HEIGHT + pollers_count, g_max_row),
|
|
|
|
get_position_for_window(THREAD_WIN_WIDTH, g_max_col));
|
|
|
|
keypad(thread_win, TRUE);
|
|
|
|
thread_panel = new_panel(thread_win);
|
2020-04-07 13:08:09 +00:00
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
top_panel(thread_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
draw_thread_win_content(thread_win, &thread_info);
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2021-12-20 16:29:14 +00:00
|
|
|
|
2021-04-14 08:25:46 +00:00
|
|
|
if (check_resize_interface(active_tab, ¤t_page)) {
|
|
|
|
/* This clear is to avoid remaining artifacts after window has been moved */
|
|
|
|
wclear(thread_win);
|
|
|
|
wclear(core_popup);
|
|
|
|
resize_interface(active_tab);
|
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
|
|
|
if (core_popup != NULL) {
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
threads_count = g_cores_info[core_info->lcore].threads.threads_count;
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
mvwin(core_popup, get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
|
|
|
|
get_position_for_window(CORE_WIN_WIDTH, g_max_col));
|
|
|
|
}
|
|
|
|
mvwin(thread_win, get_position_for_window(THREAD_WIN_HEIGHT + pollers_count, g_max_row),
|
|
|
|
get_position_for_window(THREAD_WIN_WIDTH, g_max_col));
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:00:30 +00:00
|
|
|
c = getch();
|
2020-04-07 13:08:09 +00:00
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-07-26 13:00:30 +00:00
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_dif = time_now.tv_sec - time_last;
|
|
|
|
|
|
|
|
if (time_dif >= g_sleep_time) {
|
|
|
|
time_last = time_now.tv_sec;
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
refresh_tab(active_tab, current_page);
|
2022-01-24 16:27:54 +00:00
|
|
|
if (core_popup != NULL) {
|
|
|
|
draw_core_win_content(core_popup, core_info);
|
|
|
|
}
|
2021-07-26 13:00:30 +00:00
|
|
|
draw_thread_win_content(thread_win, &thread_info);
|
|
|
|
refresh();
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
last_pollers_count = pollers_count;
|
2022-08-22 10:16:50 +00:00
|
|
|
free(thread_info.name);
|
|
|
|
free(thread_info.cpumask);
|
|
|
|
thread_info.name = NULL;
|
|
|
|
thread_info.cpumask = NULL;
|
2020-04-07 13:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(thread_panel);
|
|
|
|
delwin(thread_win);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-07-26 13:00:30 +00:00
|
|
|
show_thread(uint8_t current_page, uint8_t active_tab)
|
2020-04-07 13:08:09 +00:00
|
|
|
{
|
|
|
|
uint64_t thread_number = current_page * g_max_data_rows + g_selected_row;
|
2021-05-21 12:14:50 +00:00
|
|
|
uint64_t thread_id;
|
2020-04-07 13:08:09 +00:00
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-06-28 11:42:53 +00:00
|
|
|
assert(thread_number < g_last_threads_count);
|
2021-05-21 12:14:50 +00:00
|
|
|
thread_id = g_threads_info[thread_number].id;
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-04-07 13:08:09 +00:00
|
|
|
|
2022-01-24 16:27:54 +00:00
|
|
|
display_thread(thread_id, current_page, active_tab, NULL, NULL);
|
2020-04-07 13:08:09 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 13:49:12 +00:00
|
|
|
static void
|
2022-01-24 16:27:54 +00:00
|
|
|
show_single_thread(uint64_t thread_id, uint8_t current_page, uint8_t active_tab, WINDOW *core_popup,
|
|
|
|
struct rpc_core_info *core_info)
|
2020-12-09 13:49:12 +00:00
|
|
|
{
|
|
|
|
uint64_t i;
|
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < g_last_threads_count; i++) {
|
|
|
|
if (g_threads_info[i].id == thread_id) {
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2022-01-24 16:27:54 +00:00
|
|
|
display_thread(thread_id, current_page, active_tab, core_popup, core_info);
|
2021-02-02 09:27:16 +00:00
|
|
|
return;
|
2020-12-09 13:49:12 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-12-09 13:49:12 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 16:19:43 +00:00
|
|
|
static void
|
|
|
|
show_core(uint8_t current_page, uint8_t active_tab)
|
|
|
|
{
|
|
|
|
PANEL *core_panel;
|
|
|
|
WINDOW *core_win;
|
|
|
|
uint64_t core_number = current_page * g_max_data_rows + g_selected_row;
|
|
|
|
struct rpc_core_info *core_info = &g_cores_info[core_number];
|
|
|
|
uint64_t threads_count, i;
|
|
|
|
uint64_t thread_id = 0;
|
|
|
|
uint16_t current_threads_row;
|
|
|
|
int c;
|
2022-01-24 16:27:54 +00:00
|
|
|
long int time_last, time_dif;
|
|
|
|
struct timespec time_now;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_last = time_now.tv_sec;
|
2022-01-24 16:19:43 +00:00
|
|
|
|
|
|
|
bool stop_loop = false;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
assert(core_number < g_last_cores_count);
|
|
|
|
|
|
|
|
threads_count = g_cores_info[core_number].threads.threads_count;
|
|
|
|
|
|
|
|
core_win = newwin(threads_count + CORE_WIN_HEIGHT, CORE_WIN_WIDTH,
|
|
|
|
get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
|
|
|
|
get_position_for_window(CORE_WIN_WIDTH, g_max_col));
|
|
|
|
|
|
|
|
keypad(core_win, TRUE);
|
|
|
|
core_panel = new_panel(core_win);
|
|
|
|
|
|
|
|
top_panel(core_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
draw_core_win_content(core_win, core_info);
|
2022-01-24 16:27:54 +00:00
|
|
|
refresh();
|
2020-11-30 12:09:21 +00:00
|
|
|
|
2020-12-09 13:49:12 +00:00
|
|
|
current_threads_row = 0;
|
|
|
|
|
2020-11-30 12:09:21 +00:00
|
|
|
while (!stop_loop) {
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-06-28 11:27:00 +00:00
|
|
|
for (i = 0; i < core_info->threads.threads_count; i++) {
|
|
|
|
if (i != current_threads_row) {
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(core_win, i + 10, 1, "%s", core_info->threads.thread[i].name);
|
2020-12-09 13:49:12 +00:00
|
|
|
} else {
|
2021-06-28 11:27:00 +00:00
|
|
|
print_left(core_win, i + 10, 1, CORE_WIN_WIDTH - 2,
|
|
|
|
core_info->threads.thread[i].name, COLOR_PAIR(2));
|
2020-12-09 13:49:12 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-12-09 13:49:12 +00:00
|
|
|
|
|
|
|
wrefresh(core_win);
|
2021-04-14 08:25:46 +00:00
|
|
|
if (check_resize_interface(active_tab, ¤t_page)) {
|
|
|
|
wclear(core_win);
|
|
|
|
resize_interface(active_tab);
|
|
|
|
draw_tab_win(active_tab);
|
|
|
|
mvwin(core_win, get_position_for_window(CORE_WIN_HEIGHT + threads_count, g_max_row),
|
|
|
|
get_position_for_window(CORE_WIN_WIDTH, g_max_col));
|
|
|
|
}
|
2020-12-09 13:49:12 +00:00
|
|
|
|
2022-01-24 16:27:54 +00:00
|
|
|
c = getch();
|
2020-11-30 12:09:21 +00:00
|
|
|
switch (c) {
|
|
|
|
case 10: /* ENTER */
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-09-01 11:52:06 +00:00
|
|
|
if (core_info->threads.threads_count > 0) {
|
|
|
|
thread_id = core_info->threads.thread[current_threads_row].id;
|
|
|
|
}
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2021-05-21 12:14:50 +00:00
|
|
|
|
2021-09-01 11:52:06 +00:00
|
|
|
if (thread_id != 0) {
|
2022-01-24 16:27:54 +00:00
|
|
|
show_single_thread(thread_id, current_page, active_tab, core_win, core_info);
|
2021-09-01 11:52:06 +00:00
|
|
|
}
|
2021-04-14 07:08:19 +00:00
|
|
|
|
|
|
|
/* This refreshes tab and core_pop-up after exiting threads pop-up. */
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
refresh_tab(active_tab, current_page);
|
|
|
|
wnoutrefresh(core_win);
|
|
|
|
refresh();
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-12-09 13:49:12 +00:00
|
|
|
break;
|
2020-11-30 12:09:21 +00:00
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
2020-12-09 13:49:12 +00:00
|
|
|
case KEY_UP:
|
|
|
|
if (current_threads_row != 0) {
|
|
|
|
current_threads_row--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_DOWN:
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-06-28 11:27:00 +00:00
|
|
|
if (current_threads_row != core_info->threads.threads_count - 1) {
|
2020-12-09 13:49:12 +00:00
|
|
|
current_threads_row++;
|
|
|
|
}
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-12-09 13:49:12 +00:00
|
|
|
break;
|
2020-11-30 12:09:21 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-01-24 16:27:54 +00:00
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_dif = time_now.tv_sec - time_last;
|
|
|
|
|
|
|
|
if (time_dif >= g_sleep_time) {
|
|
|
|
time_last = time_now.tv_sec;
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
refresh_tab(active_tab, current_page);
|
|
|
|
draw_core_win_content(core_win, core_info);
|
|
|
|
refresh();
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
}
|
2020-11-30 12:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(core_panel);
|
|
|
|
delwin(core_win);
|
|
|
|
}
|
|
|
|
|
2020-11-30 12:20:37 +00:00
|
|
|
static void
|
2022-01-24 16:00:41 +00:00
|
|
|
draw_poller_win_content(WINDOW *poller_win, struct rpc_poller_info *poller_info)
|
2020-11-30 12:20:37 +00:00
|
|
|
{
|
2021-07-22 11:29:16 +00:00
|
|
|
uint64_t last_run_counter, last_busy_counter, busy_count;
|
2020-11-30 13:38:00 +00:00
|
|
|
char poller_period[MAX_TIME_STR_LEN];
|
2020-11-30 12:20:37 +00:00
|
|
|
|
|
|
|
box(poller_win, 0, 0);
|
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
print_in_middle(poller_win, 1, 0, POLLER_WIN_WIDTH, poller_info->name, COLOR_PAIR(3));
|
2020-11-30 12:20:37 +00:00
|
|
|
mvwhline(poller_win, 2, 1, ACS_HLINE, POLLER_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(poller_win, 2, POLLER_WIN_WIDTH, ACS_RTEE);
|
2020-11-30 13:38:00 +00:00
|
|
|
|
|
|
|
print_left(poller_win, 3, 2, POLLER_WIN_WIDTH, "Type: On thread:", COLOR_PAIR(5));
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(poller_win, 3, POLLER_WIN_FIRST_COL, "%s",
|
2022-01-24 16:00:41 +00:00
|
|
|
poller_type_str[poller_info->type]);
|
|
|
|
mvwprintw(poller_win, 3, POLLER_WIN_FIRST_COL + 23, "%s", poller_info->thread_name);
|
2020-11-30 13:38:00 +00:00
|
|
|
|
|
|
|
print_left(poller_win, 4, 2, POLLER_WIN_WIDTH, "Run count:", COLOR_PAIR(5));
|
2020-12-09 09:42:49 +00:00
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
last_run_counter = get_last_run_counter(poller_info->id, poller_info->thread_id);
|
|
|
|
last_busy_counter = get_last_busy_counter(poller_info->id, poller_info->thread_id);
|
2020-12-09 09:42:49 +00:00
|
|
|
if (g_interval_data) {
|
2022-01-24 16:00:41 +00:00
|
|
|
mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL, "%" PRIu64,
|
|
|
|
poller_info->run_count - last_run_counter);
|
2020-12-09 09:42:49 +00:00
|
|
|
} else {
|
2022-01-24 16:00:41 +00:00
|
|
|
mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL, "%" PRIu64, poller_info->run_count);
|
2020-12-09 09:42:49 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
if (poller_info->period_ticks != 0) {
|
2020-11-30 13:38:00 +00:00
|
|
|
print_left(poller_win, 4, 28, POLLER_WIN_WIDTH, "Period:", COLOR_PAIR(5));
|
2022-01-24 16:00:41 +00:00
|
|
|
get_time_str(poller_info->period_ticks, poller_period);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvwprintw(poller_win, 4, POLLER_WIN_FIRST_COL + 23, "%s", poller_period);
|
2020-11-30 13:38:00 +00:00
|
|
|
}
|
2020-12-08 09:46:41 +00:00
|
|
|
mvwhline(poller_win, 5, 1, ACS_HLINE, POLLER_WIN_WIDTH - 2);
|
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
busy_count = g_interval_data ? poller_info->busy_count - last_busy_counter :
|
|
|
|
poller_info->busy_count;
|
2021-07-22 11:29:16 +00:00
|
|
|
if (busy_count != 0) {
|
|
|
|
print_left(poller_win, 6, 2, POLLER_WIN_WIDTH, "Status: Busy count:", COLOR_PAIR(5));
|
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
if (g_interval_data == false && poller_info->busy_count == last_busy_counter) {
|
2021-07-22 11:29:16 +00:00
|
|
|
print_left(poller_win, 6, POLLER_WIN_FIRST_COL, POLLER_WIN_WIDTH, "Idle", COLOR_PAIR(7));
|
|
|
|
} else {
|
|
|
|
print_left(poller_win, 6, POLLER_WIN_FIRST_COL, POLLER_WIN_WIDTH, "Busy", COLOR_PAIR(6));
|
|
|
|
}
|
|
|
|
|
|
|
|
mvwprintw(poller_win, 6, POLLER_WIN_FIRST_COL + 23, "%" PRIu64, busy_count);
|
2020-12-08 09:46:41 +00:00
|
|
|
} else {
|
2021-07-22 11:29:16 +00:00
|
|
|
print_in_middle(poller_win, 6, 1, POLLER_WIN_WIDTH - 7, "Status:", COLOR_PAIR(5));
|
2020-12-08 09:46:41 +00:00
|
|
|
print_in_middle(poller_win, 6, 1, POLLER_WIN_WIDTH + 6, "Idle", COLOR_PAIR(7));
|
|
|
|
}
|
2020-11-30 12:20:37 +00:00
|
|
|
|
2022-01-24 15:43:28 +00:00
|
|
|
wnoutrefresh(poller_win);
|
2022-01-24 16:00:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-01-24 16:10:34 +00:00
|
|
|
show_poller(uint8_t current_page, uint8_t active_tab)
|
2022-01-24 16:00:41 +00:00
|
|
|
{
|
|
|
|
PANEL *poller_panel;
|
|
|
|
WINDOW *poller_win;
|
|
|
|
uint64_t poller_number = current_page * g_max_data_rows + g_selected_row;
|
|
|
|
struct rpc_poller_info *poller;
|
|
|
|
bool stop_loop = false;
|
|
|
|
int c;
|
2022-01-24 16:10:34 +00:00
|
|
|
long int time_last, time_dif;
|
|
|
|
struct timespec time_now;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_last = time_now.tv_sec;
|
|
|
|
|
2022-01-24 16:00:41 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
|
|
|
|
assert(poller_number < g_last_pollers_count);
|
|
|
|
poller = &g_pollers_info[poller_number];
|
|
|
|
|
|
|
|
poller_win = newwin(POLLER_WIN_HEIGHT, POLLER_WIN_WIDTH,
|
|
|
|
get_position_for_window(POLLER_WIN_HEIGHT, g_max_row),
|
|
|
|
get_position_for_window(POLLER_WIN_WIDTH, g_max_col));
|
|
|
|
|
|
|
|
keypad(poller_win, TRUE);
|
|
|
|
poller_panel = new_panel(poller_win);
|
|
|
|
|
|
|
|
top_panel(poller_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
draw_poller_win_content(poller_win, poller);
|
2022-01-24 16:10:34 +00:00
|
|
|
refresh();
|
2020-11-30 12:20:37 +00:00
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-11-30 12:20:37 +00:00
|
|
|
while (!stop_loop) {
|
2021-04-14 08:25:46 +00:00
|
|
|
if (check_resize_interface(active_tab, ¤t_page)) {
|
|
|
|
/* This clear is to avoid remaining artifacts after window has been moved */
|
|
|
|
wclear(poller_win);
|
|
|
|
resize_interface(active_tab);
|
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
|
|
|
mvwin(poller_win, get_position_for_window(POLLER_WIN_HEIGHT, g_max_row),
|
|
|
|
get_position_for_window(POLLER_WIN_WIDTH, g_max_col));
|
|
|
|
}
|
2022-01-24 16:10:34 +00:00
|
|
|
c = getch();
|
2020-11-30 12:20:37 +00:00
|
|
|
switch (c) {
|
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-01-24 16:10:34 +00:00
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
|
|
|
time_dif = time_now.tv_sec - time_last;
|
|
|
|
|
|
|
|
if (time_dif >= g_sleep_time) {
|
|
|
|
time_last = time_now.tv_sec;
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
refresh_tab(active_tab, current_page);
|
|
|
|
draw_poller_win_content(poller_win, poller);
|
|
|
|
refresh();
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
}
|
2020-11-30 12:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(poller_panel);
|
|
|
|
delwin(poller_win);
|
|
|
|
}
|
|
|
|
|
2022-04-11 10:24:13 +00:00
|
|
|
static uint64_t
|
|
|
|
get_max_scheduler_win_width(uint8_t sched_name_label_len, uint8_t sched_period_label_len,
|
|
|
|
uint8_t gov_name_label_len)
|
|
|
|
{
|
|
|
|
uint8_t window_borders = 4;
|
|
|
|
uint64_t s_name, s_period, g_name, max_name_len;
|
|
|
|
char scheduler_period[MAX_SCHEDULER_PERIOD_STR_LEN];
|
|
|
|
|
|
|
|
snprintf(scheduler_period, MAX_SCHEDULER_PERIOD_STR_LEN, "%" PRIu64,
|
|
|
|
g_scheduler_info.scheduler_period);
|
|
|
|
|
|
|
|
s_name = strlen(g_scheduler_info.scheduler_name) + sched_name_label_len;
|
|
|
|
if (g_scheduler_info.governor_name != NULL) {
|
|
|
|
g_name = strlen(g_scheduler_info.governor_name) + gov_name_label_len;
|
|
|
|
} else {
|
|
|
|
g_name = strlen("none") + gov_name_label_len;
|
|
|
|
}
|
|
|
|
s_period = strlen(scheduler_period) + sched_period_label_len;
|
|
|
|
|
|
|
|
max_name_len = spdk_max(s_name, g_name);
|
|
|
|
/* This function relies on the fact that scheduler/governor
|
|
|
|
* names will not change during runtime. Otherwise the scheduler
|
|
|
|
* pop-up would need dynamic resizing. */
|
|
|
|
|
|
|
|
return spdk_max(max_name_len, s_period) + window_borders;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_scheduler_popup(WINDOW *scheduler_win, uint64_t scheduler_win_width, uint8_t active_tab,
|
|
|
|
uint8_t current_page, const char *scheduler_name_label,
|
|
|
|
const char *scheduler_period_label, const char *governor_name_label)
|
|
|
|
{
|
|
|
|
char scheduler_period[MAX_SCHEDULER_PERIOD_STR_LEN];
|
|
|
|
|
|
|
|
box(scheduler_win, 0, 0);
|
|
|
|
|
|
|
|
print_left(scheduler_win, 1, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, scheduler_name_label,
|
|
|
|
COLOR_PAIR(5));
|
|
|
|
print_left(scheduler_win, 1, SCHEDULER_WIN_FIRST_COL + strlen(scheduler_name_label),
|
|
|
|
scheduler_win_width,
|
|
|
|
g_scheduler_info.scheduler_name, COLOR_PAIR(3));
|
|
|
|
|
|
|
|
mvwhline(scheduler_win, 2, 1, ACS_HLINE, scheduler_win_width - 2);
|
|
|
|
mvwaddch(scheduler_win, 2, scheduler_win_width, ACS_RTEE);
|
|
|
|
|
|
|
|
print_left(scheduler_win, 3, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, scheduler_period_label,
|
|
|
|
COLOR_PAIR(5));
|
|
|
|
snprintf(scheduler_period, MAX_SCHEDULER_PERIOD_STR_LEN, "%" PRIu64,
|
|
|
|
g_scheduler_info.scheduler_period);
|
|
|
|
mvwprintw(scheduler_win, 3, SCHEDULER_WIN_FIRST_COL + strlen(scheduler_period_label), "%s",
|
|
|
|
scheduler_period);
|
|
|
|
|
|
|
|
mvwhline(scheduler_win, 4, 1, ACS_HLINE, scheduler_win_width - 2);
|
|
|
|
mvwaddch(scheduler_win, 4, scheduler_win_width, ACS_RTEE);
|
|
|
|
|
|
|
|
print_left(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL, scheduler_win_width, governor_name_label,
|
|
|
|
COLOR_PAIR(5));
|
|
|
|
|
|
|
|
if (g_scheduler_info.governor_name != NULL) {
|
|
|
|
mvwprintw(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL + strlen(governor_name_label), "%s",
|
|
|
|
g_scheduler_info.governor_name);
|
|
|
|
} else {
|
|
|
|
mvwprintw(scheduler_win, 5, SCHEDULER_WIN_FIRST_COL + strlen(governor_name_label), "%s", "none");
|
|
|
|
}
|
|
|
|
|
|
|
|
refresh_tab(active_tab, current_page);
|
|
|
|
wnoutrefresh(scheduler_win);
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
show_scheduler(uint8_t active_tab, uint8_t current_page)
|
|
|
|
{
|
|
|
|
PANEL *scheduler_panel;
|
|
|
|
WINDOW *scheduler_win;
|
|
|
|
uint64_t scheduler_win_width;
|
|
|
|
bool stop_loop = false;
|
|
|
|
int c;
|
|
|
|
const char *scheduler_name_label = "Scheduler: ";
|
|
|
|
const char *scheduler_period_label = "Period [us]: ";
|
|
|
|
const char *governor_name_label = "Governor: ";
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
scheduler_win_width = get_max_scheduler_win_width(strlen(scheduler_name_label),
|
|
|
|
strlen(scheduler_period_label),
|
|
|
|
strlen(governor_name_label));
|
|
|
|
|
|
|
|
scheduler_win = newwin(SCHEDULER_WIN_HEIGHT, scheduler_win_width,
|
|
|
|
get_position_for_window(SCHEDULER_WIN_HEIGHT, g_max_row),
|
|
|
|
get_position_for_window(scheduler_win_width, g_max_col));
|
|
|
|
|
|
|
|
keypad(scheduler_win, TRUE);
|
|
|
|
scheduler_panel = new_panel(scheduler_win);
|
|
|
|
|
|
|
|
top_panel(scheduler_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
|
|
|
|
draw_scheduler_popup(scheduler_win, scheduler_win_width, active_tab, current_page,
|
|
|
|
scheduler_name_label, scheduler_period_label, governor_name_label);
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
|
|
|
|
while (!stop_loop) {
|
|
|
|
c = wgetch(scheduler_win);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(scheduler_panel);
|
|
|
|
delwin(scheduler_win);
|
|
|
|
}
|
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
static void *
|
|
|
|
data_thread_routine(void *arg)
|
|
|
|
{
|
|
|
|
int rc;
|
2021-04-14 06:48:19 +00:00
|
|
|
uint64_t refresh_rate;
|
2021-02-02 09:27:16 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
if (g_quit_app) {
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
break;
|
|
|
|
}
|
2021-04-14 06:48:19 +00:00
|
|
|
|
|
|
|
if (g_sleep_time == 0) {
|
|
|
|
/* Give display thread time to redraw all windows */
|
|
|
|
refresh_rate = SPDK_SEC_TO_USEC / 100;
|
|
|
|
} else {
|
|
|
|
refresh_rate = g_sleep_time * SPDK_SEC_TO_USEC;
|
|
|
|
}
|
2021-04-14 14:58:11 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2021-02-02 09:27:16 +00:00
|
|
|
|
2021-05-05 13:47:19 +00:00
|
|
|
/* Get data from RPC for each object type.
|
|
|
|
* Start with cores since their number should not change. */
|
|
|
|
rc = get_cores_data();
|
|
|
|
if (rc) {
|
2021-10-27 05:36:43 +00:00
|
|
|
print_bottom_message("ERROR occurred while getting cores data");
|
2021-05-05 13:47:19 +00:00
|
|
|
}
|
2021-04-14 14:58:11 +00:00
|
|
|
rc = get_thread_data();
|
2021-02-02 09:27:16 +00:00
|
|
|
if (rc) {
|
2021-10-27 05:36:43 +00:00
|
|
|
print_bottom_message("ERROR occurred while getting threads data");
|
2021-02-02 09:27:16 +00:00
|
|
|
}
|
|
|
|
|
2021-04-14 14:58:11 +00:00
|
|
|
rc = get_pollers_data();
|
|
|
|
if (rc) {
|
2021-10-27 05:36:43 +00:00
|
|
|
print_bottom_message("ERROR occurred while getting pollers data");
|
2021-04-14 14:58:11 +00:00
|
|
|
}
|
2021-01-15 16:14:16 +00:00
|
|
|
rc = get_scheduler_data();
|
|
|
|
if (rc) {
|
|
|
|
print_bottom_message("ERROR occurred while getting scheduler data");
|
|
|
|
}
|
2021-04-14 14:58:11 +00:00
|
|
|
|
2021-04-14 06:48:19 +00:00
|
|
|
usleep(refresh_rate);
|
2021-02-02 09:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-26 10:30:37 +00:00
|
|
|
static void
|
|
|
|
help_window_display(void)
|
|
|
|
{
|
|
|
|
PANEL *help_panel;
|
|
|
|
WINDOW *help_win;
|
|
|
|
bool stop_loop = false;
|
|
|
|
int c;
|
|
|
|
uint64_t row = 1, col = 2, desc_second_row_col = 26, header_footer_col = 0;
|
|
|
|
|
|
|
|
help_win = newwin(HELP_WIN_HEIGHT, HELP_WIN_WIDTH,
|
|
|
|
get_position_for_window(HELP_WIN_HEIGHT, g_max_row),
|
|
|
|
get_position_for_window(HELP_WIN_WIDTH, g_max_col));
|
|
|
|
help_panel = new_panel(help_win);
|
|
|
|
top_panel(help_panel);
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
|
|
|
|
box(help_win, 0, 0);
|
|
|
|
|
|
|
|
/* Header */
|
|
|
|
print_in_middle(help_win, row, header_footer_col, HELP_WIN_WIDTH, "HELP", COLOR_PAIR(3));
|
|
|
|
mvwhline(help_win, 2, 1, ACS_HLINE, HELP_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(help_win, 2, HELP_WIN_WIDTH, ACS_RTEE);
|
|
|
|
row = 3;
|
|
|
|
|
|
|
|
/* Content */
|
|
|
|
print_left(help_win, row, col, HELP_WIN_WIDTH, "MENU options", COLOR_PAIR(5));
|
|
|
|
print_left(help_win, ++row, ++col, HELP_WIN_WIDTH, "[q] Quit - quit this application",
|
|
|
|
COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Tab] Next tab - switch to next tab", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[1-3] Select tab - switch to THREADS, POLLERS or CORES tab", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[PgUp] Previous page - scroll up to previous page", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[PgDown] Next page - scroll down to next page", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Up] Arrow key - go to previous data row", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Down] Arrow key - go to next data row", COLOR_PAIR(10));
|
2021-10-13 16:23:22 +00:00
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Right] Arrow key - go to second sorting window", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Left] Arrow key - close second sorting window", COLOR_PAIR(10));
|
2021-01-26 10:30:37 +00:00
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[c] Columns - choose data columns to display", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[s] Sorting - change sorting by column", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[r] Refresh rate - set refresh rate <0, 255> in seconds", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, desc_second_row_col, HELP_WIN_WIDTH, "that value in seconds",
|
|
|
|
COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[Enter] Item details - show current data row details (Enter to open, Esc to close)",
|
|
|
|
COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[t] Total/Interval - switch to display data measured from the start of SPDK", COLOR_PAIR(10));
|
|
|
|
print_left(help_win, ++row, desc_second_row_col, HELP_WIN_WIDTH,
|
|
|
|
"application or last refresh", COLOR_PAIR(10));
|
2022-04-11 10:24:13 +00:00
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH,
|
|
|
|
"[g] Scheduler pop-up - display current scheduler information", COLOR_PAIR(10));
|
2021-01-26 10:30:37 +00:00
|
|
|
print_left(help_win, ++row, col, HELP_WIN_WIDTH, "[h] Help - show this help window",
|
|
|
|
COLOR_PAIR(10));
|
|
|
|
|
|
|
|
/* Footer */
|
|
|
|
mvwhline(help_win, HELP_WIN_HEIGHT - 3, 1, ACS_HLINE, HELP_WIN_WIDTH - 2);
|
|
|
|
mvwaddch(help_win, HELP_WIN_HEIGHT - 3, HELP_WIN_WIDTH, ACS_RTEE);
|
|
|
|
|
|
|
|
print_in_middle(help_win, HELP_WIN_HEIGHT - 2, header_footer_col, HELP_WIN_WIDTH,
|
|
|
|
"[Esc] Close this window", COLOR_PAIR(10));
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
wrefresh(help_win);
|
|
|
|
|
|
|
|
while (!stop_loop) {
|
|
|
|
c = wgetch(help_win);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 27: /* ESC */
|
|
|
|
stop_loop = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
del_panel(help_panel);
|
|
|
|
delwin(help_win);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-11-25 10:31:14 +00:00
|
|
|
static void
|
|
|
|
refresh_after_popup(uint8_t active_tab, uint8_t *max_pages, uint8_t current_page)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* After closing pop-up there would be unrefreshed parts
|
|
|
|
* of the tab, so this is to refresh them */
|
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
*max_pages = refresh_tab(active_tab, current_page);
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
|
|
|
top_panel(g_panels[active_tab]);
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
wclear(g_tab_win[i]);
|
|
|
|
wresize(g_tab_win[i], TAB_WIN_HEIGHT,
|
|
|
|
(g_max_col - (TABS_SPACING * NUMBER_OF_TABS)) / NUMBER_OF_TABS);
|
|
|
|
mvwin(g_tab_win[i], TAB_WIN_LOCATION_ROW, 1 + (g_max_col / NUMBER_OF_TABS) * i);
|
|
|
|
draw_tab_win(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
update_panels();
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
static void
|
2021-02-02 09:27:16 +00:00
|
|
|
show_stats(pthread_t *data_thread)
|
2020-02-28 13:00:08 +00:00
|
|
|
{
|
2020-03-09 12:14:43 +00:00
|
|
|
const int CURRENT_PAGE_STR_LEN = 50;
|
2020-04-10 05:32:35 +00:00
|
|
|
long int time_last, time_dif;
|
|
|
|
struct timespec time_now;
|
2021-02-02 09:27:16 +00:00
|
|
|
int c;
|
2020-02-28 13:00:08 +00:00
|
|
|
uint8_t active_tab = THREADS_TAB;
|
2020-03-09 12:14:43 +00:00
|
|
|
uint8_t current_page = 0;
|
|
|
|
uint8_t max_pages = 1;
|
2021-06-22 11:44:20 +00:00
|
|
|
uint64_t i;
|
2020-03-09 12:14:43 +00:00
|
|
|
char current_page_str[CURRENT_PAGE_STR_LEN];
|
2020-04-10 05:32:35 +00:00
|
|
|
bool force_refresh = true;
|
|
|
|
|
2021-07-26 12:52:37 +00:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
2020-04-10 05:32:35 +00:00
|
|
|
time_last = time_now.tv_sec;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
switch_tab(THREADS_TAB);
|
|
|
|
|
|
|
|
while (1) {
|
2021-04-19 12:03:16 +00:00
|
|
|
check_resize_interface(active_tab, ¤t_page);
|
2020-02-28 13:00:08 +00:00
|
|
|
|
2021-07-26 12:52:37 +00:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &time_now);
|
2021-05-19 10:58:35 +00:00
|
|
|
time_dif = time_now.tv_sec - time_last;
|
|
|
|
if (time_dif < 0) {
|
|
|
|
time_dif = g_sleep_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time_dif >= g_sleep_time || force_refresh) {
|
|
|
|
time_last = time_now.tv_sec;
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
2021-05-19 10:58:35 +00:00
|
|
|
max_pages = refresh_tab(active_tab, current_page);
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2021-05-19 10:58:35 +00:00
|
|
|
|
|
|
|
snprintf(current_page_str, CURRENT_PAGE_STR_LEN - 1, "Page: %d/%d", current_page + 1, max_pages);
|
2021-11-19 08:07:31 +00:00
|
|
|
mvprintw(g_max_row - 1, 1, "%s", current_page_str);
|
2021-05-19 10:58:35 +00:00
|
|
|
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
c = getch();
|
|
|
|
if (c == 'q') {
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_mutex_lock(&g_thread_lock);
|
|
|
|
g_quit_app = true;
|
|
|
|
pthread_mutex_unlock(&g_thread_lock);
|
2020-02-28 13:00:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-10 05:32:35 +00:00
|
|
|
force_refresh = true;
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
switch (c) {
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
active_tab = c - '1';
|
2020-03-09 12:14:43 +00:00
|
|
|
current_page = 0;
|
2020-04-07 10:44:59 +00:00
|
|
|
g_selected_row = 0;
|
2020-02-28 13:00:08 +00:00
|
|
|
switch_tab(active_tab);
|
|
|
|
break;
|
2020-04-22 08:42:30 +00:00
|
|
|
case '\t':
|
|
|
|
if (active_tab < NUMBER_OF_TABS - 1) {
|
|
|
|
active_tab++;
|
|
|
|
} else {
|
|
|
|
active_tab = THREADS_TAB;
|
|
|
|
}
|
2021-02-04 09:30:00 +00:00
|
|
|
g_selected_row = 0;
|
2020-04-22 08:42:30 +00:00
|
|
|
current_page = 0;
|
|
|
|
switch_tab(active_tab);
|
|
|
|
break;
|
2020-03-27 09:13:14 +00:00
|
|
|
case 's':
|
2021-10-13 16:21:58 +00:00
|
|
|
sort_type2(active_tab, COL_THREADS_NONE);
|
|
|
|
change_sorting(active_tab, 0, NULL);
|
2020-03-27 09:13:14 +00:00
|
|
|
break;
|
2020-04-20 09:14:19 +00:00
|
|
|
case 'c':
|
|
|
|
filter_columns(active_tab);
|
|
|
|
break;
|
2020-04-10 05:32:35 +00:00
|
|
|
case 'r':
|
|
|
|
change_refresh_rate();
|
|
|
|
break;
|
2020-12-09 09:42:49 +00:00
|
|
|
case 't':
|
|
|
|
g_interval_data = !g_interval_data;
|
|
|
|
break;
|
2022-04-11 10:24:13 +00:00
|
|
|
case 'g':
|
|
|
|
show_scheduler(active_tab, current_page);
|
|
|
|
break;
|
2020-04-07 10:44:59 +00:00
|
|
|
case KEY_NPAGE: /* PgDown */
|
2020-03-09 12:14:43 +00:00
|
|
|
if (current_page + 1 < max_pages) {
|
|
|
|
current_page++;
|
|
|
|
}
|
|
|
|
wclear(g_tabs[active_tab]);
|
2020-04-07 10:44:59 +00:00
|
|
|
g_selected_row = 0;
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
2020-03-09 12:14:43 +00:00
|
|
|
break;
|
2020-04-07 10:44:59 +00:00
|
|
|
case KEY_PPAGE: /* PgUp */
|
2020-03-09 12:14:43 +00:00
|
|
|
if (current_page > 0) {
|
|
|
|
current_page--;
|
|
|
|
}
|
|
|
|
wclear(g_tabs[active_tab]);
|
2020-04-07 10:44:59 +00:00
|
|
|
g_selected_row = 0;
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
2020-03-09 12:14:43 +00:00
|
|
|
break;
|
2020-04-07 10:44:59 +00:00
|
|
|
case KEY_UP: /* Arrow up */
|
|
|
|
if (g_selected_row > 0) {
|
|
|
|
g_selected_row--;
|
2022-11-25 10:32:32 +00:00
|
|
|
} else if (g_selected_row == 0) {
|
|
|
|
if (current_page > 0) {
|
|
|
|
current_page--;
|
|
|
|
g_selected_row = g_max_data_rows - 1;
|
|
|
|
wclear(g_tabs[active_tab]);
|
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
|
|
|
}
|
2020-04-07 10:44:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_DOWN: /* Arrow down */
|
|
|
|
if (g_selected_row < g_max_selected_row) {
|
|
|
|
g_selected_row++;
|
2022-11-25 10:32:32 +00:00
|
|
|
} else if (g_selected_row == g_max_selected_row) {
|
|
|
|
if (current_page + 1 < max_pages) {
|
|
|
|
current_page++;
|
|
|
|
g_selected_row = 0;
|
|
|
|
wclear(g_tabs[active_tab]);
|
|
|
|
draw_tabs(active_tab, g_current_sort_col[active_tab], g_current_sort_col2[active_tab]);
|
|
|
|
}
|
2020-04-07 10:44:59 +00:00
|
|
|
}
|
|
|
|
break;
|
2020-04-07 13:08:09 +00:00
|
|
|
case 10: /* Enter */
|
|
|
|
if (active_tab == THREADS_TAB) {
|
2021-07-26 13:00:30 +00:00
|
|
|
show_thread(current_page, active_tab);
|
2020-11-30 12:09:21 +00:00
|
|
|
} else if (active_tab == CORES_TAB) {
|
2021-07-26 13:00:30 +00:00
|
|
|
show_core(current_page, active_tab);
|
2020-11-30 12:20:37 +00:00
|
|
|
} else if (active_tab == POLLERS_TAB) {
|
2022-01-24 16:10:34 +00:00
|
|
|
show_poller(current_page, active_tab);
|
2020-04-07 13:08:09 +00:00
|
|
|
}
|
2021-04-14 07:08:19 +00:00
|
|
|
snprintf(current_page_str, CURRENT_PAGE_STR_LEN - 1, "Page: %d/%d", current_page + 1, max_pages);
|
|
|
|
mvprintw(g_max_row - 1, 1, "%s", current_page_str);
|
2022-11-25 10:31:14 +00:00
|
|
|
refresh_after_popup(active_tab, &max_pages, current_page);
|
2020-04-07 13:08:09 +00:00
|
|
|
break;
|
2021-01-26 10:30:37 +00:00
|
|
|
case 'h':
|
|
|
|
help_window_display();
|
2022-11-25 10:31:14 +00:00
|
|
|
refresh_after_popup(active_tab, &max_pages, current_page);
|
2021-01-26 10:30:37 +00:00
|
|
|
break;
|
2020-02-28 13:00:08 +00:00
|
|
|
default:
|
2020-04-10 05:32:35 +00:00
|
|
|
force_refresh = false;
|
2020-02-28 13:00:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-02-02 09:27:16 +00:00
|
|
|
|
|
|
|
pthread_join(*data_thread, NULL);
|
|
|
|
|
2021-04-14 14:08:50 +00:00
|
|
|
free_poller_history();
|
2021-05-20 06:47:39 +00:00
|
|
|
|
|
|
|
/* Free memory holding current data states before quitting application */
|
2021-06-22 11:44:20 +00:00
|
|
|
for (i = 0; i < g_last_pollers_count; i++) {
|
|
|
|
free_rpc_poller(&g_pollers_info[i]);
|
|
|
|
}
|
2021-06-28 11:42:53 +00:00
|
|
|
for (i = 0; i < g_last_threads_count; i++) {
|
|
|
|
free_rpc_threads_stats(&g_threads_info[i]);
|
|
|
|
}
|
2021-06-28 11:27:00 +00:00
|
|
|
free_rpc_core_info(g_cores_info, g_last_cores_count);
|
2021-01-15 16:14:16 +00:00
|
|
|
free_rpc_scheduler(&g_scheduler_info);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_interface(void)
|
|
|
|
{
|
|
|
|
int i;
|
2021-02-01 13:30:55 +00:00
|
|
|
uint16_t required_size = WINDOW_HEADER + 1;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
getmaxyx(stdscr, g_max_row, g_max_col);
|
2021-02-01 13:30:55 +00:00
|
|
|
g_max_row = spdk_max(g_max_row, required_size);
|
|
|
|
g_data_win_size = g_max_row - required_size;
|
2020-03-09 12:14:43 +00:00
|
|
|
g_max_data_rows = g_max_row - WINDOW_HEADER;
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
g_menu_win = newwin(MENU_WIN_HEIGHT, g_max_col, g_max_row - MENU_WIN_HEIGHT - 1,
|
|
|
|
MENU_WIN_LOCATION_COL);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(g_menu_win != NULL);
|
2020-02-28 13:00:08 +00:00
|
|
|
draw_menu_win();
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_TABS; i++) {
|
|
|
|
g_tab_win[i] = newwin(TAB_WIN_HEIGHT, g_max_col / NUMBER_OF_TABS - TABS_SPACING,
|
|
|
|
TAB_WIN_LOCATION_ROW, g_max_col / NUMBER_OF_TABS * i + 1);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(g_tab_win[i] != NULL);
|
2020-02-28 13:00:08 +00:00
|
|
|
draw_tab_win(i);
|
|
|
|
|
|
|
|
g_tabs[i] = newwin(g_max_row - MENU_WIN_HEIGHT - TAB_WIN_HEIGHT - 2, g_max_col, TABS_LOCATION_ROW,
|
|
|
|
TABS_LOCATION_COL);
|
2021-10-13 16:21:58 +00:00
|
|
|
draw_tabs(i, g_current_sort_col[i], g_current_sort_col2[i]);
|
2020-03-27 09:13:14 +00:00
|
|
|
g_panels[i] = new_panel(g_tabs[i]);
|
2020-11-09 02:41:45 +00:00
|
|
|
assert(g_panels[i] != NULL);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
update_panels();
|
|
|
|
doupdate();
|
|
|
|
}
|
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
static void
|
|
|
|
finish(int sig)
|
2020-04-22 13:55:52 +00:00
|
|
|
{
|
|
|
|
/* End ncurses mode */
|
|
|
|
endwin();
|
|
|
|
spdk_jsonrpc_client_close(g_rpc_client);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
static void
|
|
|
|
setup_ncurses(void)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
noecho();
|
2020-04-10 05:32:35 +00:00
|
|
|
timeout(1);
|
2020-02-28 13:00:08 +00:00
|
|
|
curs_set(0);
|
2020-04-07 10:44:59 +00:00
|
|
|
keypad(stdscr, TRUE);
|
2020-02-28 13:00:08 +00:00
|
|
|
start_color();
|
|
|
|
init_pair(1, COLOR_BLACK, COLOR_GREEN);
|
|
|
|
init_pair(2, COLOR_BLACK, COLOR_WHITE);
|
2020-03-27 09:13:14 +00:00
|
|
|
init_pair(3, COLOR_YELLOW, COLOR_BLACK);
|
|
|
|
init_pair(4, COLOR_BLACK, COLOR_YELLOW);
|
2020-04-07 13:08:09 +00:00
|
|
|
init_pair(5, COLOR_GREEN, COLOR_BLACK);
|
2020-12-08 09:46:41 +00:00
|
|
|
init_pair(6, COLOR_RED, COLOR_BLACK);
|
|
|
|
init_pair(7, COLOR_BLUE, COLOR_BLACK);
|
|
|
|
init_pair(8, COLOR_RED, COLOR_WHITE);
|
|
|
|
init_pair(9, COLOR_BLUE, COLOR_WHITE);
|
2021-01-26 10:30:37 +00:00
|
|
|
init_pair(10, COLOR_WHITE, COLOR_BLACK);
|
2020-02-28 13:00:08 +00:00
|
|
|
|
|
|
|
if (has_colors() == FALSE) {
|
|
|
|
endwin();
|
|
|
|
printf("Your terminal does not support color\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2020-04-22 13:55:52 +00:00
|
|
|
|
2021-11-25 01:40:57 +00:00
|
|
|
/* Handle signals to exit gracefully cleaning up ncurses */
|
2020-04-22 13:55:52 +00:00
|
|
|
(void) signal(SIGINT, finish);
|
|
|
|
(void) signal(SIGPIPE, finish);
|
|
|
|
(void) signal(SIGABRT, finish);
|
2020-02-28 13:00:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-14 07:01:41 +00:00
|
|
|
static void
|
|
|
|
usage(const char *program_name)
|
|
|
|
{
|
|
|
|
printf("%s [options]", program_name);
|
|
|
|
printf("\n");
|
|
|
|
printf("options:\n");
|
2021-02-08 21:06:27 +00:00
|
|
|
printf(" -r <path> RPC connect address (default: /var/tmp/spdk.sock)\n");
|
2020-04-14 07:01:41 +00:00
|
|
|
printf(" -h show this usage\n");
|
|
|
|
}
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
static int
|
|
|
|
rpc_decode_tick_rate(struct spdk_json_val *val, uint64_t *tick_rate)
|
|
|
|
{
|
|
|
|
struct t_rate {
|
|
|
|
uint64_t tr;
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct spdk_json_object_decoder rpc_tick_rate_decoder[] = {
|
|
|
|
{"tick_rate", offsetof(struct t_rate, tr), spdk_json_decode_uint64}
|
|
|
|
};
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
struct t_rate tmp;
|
|
|
|
|
|
|
|
rc = spdk_json_decode_object_relaxed(val, rpc_tick_rate_decoder,
|
|
|
|
SPDK_COUNTOF(rpc_tick_rate_decoder), &tmp);
|
|
|
|
|
|
|
|
*tick_rate = tmp.tr;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-03-29 12:39:46 +00:00
|
|
|
static int
|
2021-02-02 09:27:16 +00:00
|
|
|
wait_init(pthread_t *data_thread)
|
2021-03-29 12:39:46 +00:00
|
|
|
{
|
|
|
|
struct spdk_jsonrpc_client_response *json_resp = NULL;
|
|
|
|
char *uninit_log = "Waiting for SPDK target application to initialize...",
|
|
|
|
*uninit_error = "Unable to read SPDK application state!";
|
|
|
|
int c, max_col, rc = 0;
|
2021-06-28 11:27:00 +00:00
|
|
|
uint64_t tick_rate;
|
2021-03-29 12:39:46 +00:00
|
|
|
|
|
|
|
max_col = getmaxx(stdscr);
|
|
|
|
print_in_middle(stdscr, FIRST_DATA_ROW, 1, max_col, uninit_log, COLOR_PAIR(5));
|
|
|
|
rc = rpc_send_req("framework_wait_init", &json_resp);
|
|
|
|
if (rc) {
|
|
|
|
while (1) {
|
|
|
|
print_in_middle(stdscr, FIRST_DATA_ROW, 1, max_col, uninit_error, COLOR_PAIR(8));
|
|
|
|
c = getch();
|
|
|
|
if (c == 'q') {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
2021-02-02 09:27:16 +00:00
|
|
|
|
|
|
|
rc = pthread_mutex_init(&g_thread_lock, NULL);
|
|
|
|
if (rc) {
|
|
|
|
fprintf(stderr, "mutex lock failed to initialize: %d\n", errno);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-06-28 11:42:53 +00:00
|
|
|
memset(&g_threads_info, 0, sizeof(struct rpc_thread_info) * RPC_MAX_THREADS);
|
2021-06-28 11:27:00 +00:00
|
|
|
memset(&g_cores_info, 0, sizeof(struct rpc_core_info) * RPC_MAX_CORES);
|
|
|
|
|
|
|
|
/* Decode tick rate */
|
|
|
|
rc = rpc_send_req("framework_get_reactors", &json_resp);
|
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rpc_decode_tick_rate(json_resp->result, &tick_rate)) {
|
2021-08-26 15:29:09 +00:00
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
2021-06-28 11:27:00 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-08-26 15:29:09 +00:00
|
|
|
spdk_jsonrpc_client_free_response(json_resp);
|
|
|
|
|
2021-06-28 11:27:00 +00:00
|
|
|
g_tick_rate = tick_rate;
|
2021-02-02 09:27:16 +00:00
|
|
|
|
|
|
|
/* This is to get first batch of data for display functions.
|
|
|
|
* Since data thread makes RPC calls that take more time than
|
2021-04-14 14:58:11 +00:00
|
|
|
* startup of display functions on main thread, without these
|
|
|
|
* calls both threads would be subject to a race condition. */
|
|
|
|
rc = get_thread_data();
|
|
|
|
if (rc) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = get_pollers_data();
|
|
|
|
if (rc) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = get_cores_data();
|
2021-02-02 09:27:16 +00:00
|
|
|
if (rc) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = pthread_create(data_thread, NULL, &data_thread_routine, NULL);
|
|
|
|
if (rc) {
|
|
|
|
fprintf(stderr, "data thread creation failed: %d\n", errno);
|
|
|
|
return -1;
|
|
|
|
}
|
2021-03-29 12:39:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-06-22 21:35:04 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2020-04-14 07:01:41 +00:00
|
|
|
{
|
2021-03-29 12:39:46 +00:00
|
|
|
int op, rc;
|
2020-04-14 07:01:41 +00:00
|
|
|
char *socket = SPDK_DEFAULT_RPC_ADDR;
|
2021-02-02 09:27:16 +00:00
|
|
|
pthread_t data_thread;
|
2020-04-14 07:01:41 +00:00
|
|
|
|
|
|
|
while ((op = getopt(argc, argv, "r:h")) != -1) {
|
|
|
|
switch (op) {
|
|
|
|
case 'r':
|
|
|
|
socket = optarg;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
2021-02-08 21:09:08 +00:00
|
|
|
return op == 'h' ? 0 : 1;
|
2020-04-14 07:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-10 17:48:35 +00:00
|
|
|
g_rpc_client = spdk_jsonrpc_client_connect(socket, socket[0] == '/' ? AF_UNIX : AF_INET);
|
2020-04-14 07:01:41 +00:00
|
|
|
if (!g_rpc_client) {
|
|
|
|
fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-02-28 13:00:08 +00:00
|
|
|
initscr();
|
2020-04-20 09:14:19 +00:00
|
|
|
init_str_len();
|
2020-02-28 13:00:08 +00:00
|
|
|
setup_ncurses();
|
|
|
|
draw_interface();
|
2021-03-29 12:39:46 +00:00
|
|
|
|
2021-02-02 09:27:16 +00:00
|
|
|
rc = wait_init(&data_thread);
|
2021-03-29 12:39:46 +00:00
|
|
|
if (!rc) {
|
2021-02-02 09:27:16 +00:00
|
|
|
show_stats(&data_thread);
|
2021-03-29 12:39:46 +00:00
|
|
|
}
|
2020-04-14 07:01:41 +00:00
|
|
|
|
2020-04-22 13:55:52 +00:00
|
|
|
finish(0);
|
2020-04-14 07:01:41 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|