spdk_top: Make data relative to last refresh
Signed-off-by: Maciej Szwed <maciej.szwed@intel.com> Change-Id: Icea3c66173f3d7bedcb34dbe353b7753885c06ad Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1776 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
cb7ed09459
commit
a2079b3f7d
@ -95,10 +95,31 @@ struct col_desc {
|
||||
bool disabled;
|
||||
};
|
||||
|
||||
struct run_counter_history {
|
||||
char *poller_name;
|
||||
uint64_t thread_id;
|
||||
uint64_t last_run_counter;
|
||||
TAILQ_ENTRY(run_counter_history) link;
|
||||
};
|
||||
|
||||
struct core_info {
|
||||
uint32_t core;
|
||||
char core_mask[MAX_CORE_MASK_STR_LEN];
|
||||
uint64_t threads_count;
|
||||
uint64_t pollers_count;
|
||||
uint64_t idle;
|
||||
uint64_t last_idle;
|
||||
uint64_t busy;
|
||||
uint64_t last_busy;
|
||||
};
|
||||
|
||||
struct rpc_thread_info *g_thread_info[MAX_THREADS];
|
||||
const char *poller_type_str[SPDK_POLLER_TYPES_COUNT] = {"Active", "Timed", "Paused"};
|
||||
const char *g_tab_title[NUMBER_OF_TABS] = {"[1] THREADS", "[2] POLLERS", "[3] CORES"};
|
||||
struct spdk_jsonrpc_client *g_rpc_client;
|
||||
static TAILQ_HEAD(, run_counter_history) g_run_counter_history = TAILQ_HEAD_INITIALIZER(
|
||||
g_run_counter_history);
|
||||
struct core_info g_cores_history[RPC_MAX_CORES];
|
||||
WINDOW *g_menu_win, *g_tab_win[NUMBER_OF_TABS], *g_tabs[NUMBER_OF_TABS];
|
||||
PANEL *g_panels[NUMBER_OF_TABS];
|
||||
uint16_t g_max_row, g_max_col;
|
||||
@ -131,22 +152,15 @@ static struct col_desc g_col_desc[NUMBER_OF_TABS][TABS_COL_COUNT] = {
|
||||
}
|
||||
};
|
||||
|
||||
struct core_info {
|
||||
uint32_t core;
|
||||
char core_mask[MAX_CORE_MASK_STR_LEN];
|
||||
uint64_t threads_count;
|
||||
uint64_t pollers_count;
|
||||
uint64_t idle;
|
||||
uint64_t busy;
|
||||
};
|
||||
|
||||
struct rpc_thread_info {
|
||||
char *name;
|
||||
uint64_t id;
|
||||
uint32_t core_num;
|
||||
char *cpumask;
|
||||
uint64_t busy;
|
||||
uint64_t last_busy;
|
||||
uint64_t idle;
|
||||
uint64_t last_idle;
|
||||
uint64_t active_pollers_count;
|
||||
uint64_t timed_pollers_count;
|
||||
uint64_t paused_pollers_count;
|
||||
@ -170,6 +184,7 @@ struct rpc_poller_info {
|
||||
uint64_t period_ticks;
|
||||
enum spdk_poller_type type;
|
||||
char thread_name[MAX_THREAD_NAME];
|
||||
uint64_t thread_id;
|
||||
};
|
||||
|
||||
struct rpc_pollers {
|
||||
@ -510,7 +525,6 @@ get_data(void)
|
||||
}
|
||||
|
||||
/* Decode json */
|
||||
memset(&g_threads_stats, 0, sizeof(g_threads_stats));
|
||||
if (spdk_json_decode_object(json_resp->result, rpc_threads_stats_decoders,
|
||||
SPDK_COUNTOF(rpc_threads_stats_decoders), &g_threads_stats)) {
|
||||
rc = -EINVAL;
|
||||
@ -802,6 +816,7 @@ refresh_threads_tab(uint8_t current_page)
|
||||
uint16_t j;
|
||||
uint16_t col;
|
||||
uint8_t max_pages, item_index;
|
||||
static uint8_t last_page = 0;
|
||||
char pollers_number[MAX_POLLER_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN],
|
||||
busy_time[MAX_TIME_STR_LEN], core_str[MAX_CORE_MASK_STR_LEN];
|
||||
struct rpc_thread_info *thread_info[g_threads_stats.threads.threads_count];
|
||||
@ -824,6 +839,16 @@ refresh_threads_tab(uint8_t current_page)
|
||||
* handle copying threads list below */
|
||||
memcpy(thread_info, &g_thread_info[1], sizeof(struct rpc_thread_info *) * threads_count);
|
||||
|
||||
if (last_page != current_page) {
|
||||
for (i = 0; i < threads_count; i++) {
|
||||
/* Thread IDs start from 1, so we have to do i + 1 */
|
||||
g_threads_stats.threads.thread_info[i].last_idle = g_thread_info[i + 1]->idle;
|
||||
g_threads_stats.threads.thread_info[i].last_busy = g_thread_info[i + 1]->busy;
|
||||
}
|
||||
|
||||
last_page = current_page;
|
||||
}
|
||||
|
||||
max_pages = (threads_count + g_max_data_rows - 1) / g_max_data_rows;
|
||||
|
||||
qsort(thread_info, threads_count, sizeof(thread_info[0]), sort_threads);
|
||||
@ -870,22 +895,58 @@ refresh_threads_tab(uint8_t current_page)
|
||||
}
|
||||
|
||||
if (!col_desc[5].disabled) {
|
||||
get_time_str(thread_info[i]->idle, idle_time);
|
||||
get_time_str(thread_info[i]->idle - thread_info[i]->last_idle, idle_time);
|
||||
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
||||
col_desc[5].max_data_string, ALIGN_RIGHT, idle_time);
|
||||
col += col_desc[5].max_data_string + 2;
|
||||
col += col_desc[5].max_data_string;
|
||||
thread_info[i]->last_idle = thread_info[i]->idle;
|
||||
}
|
||||
|
||||
if (!col_desc[6].disabled) {
|
||||
get_time_str(thread_info[i]->busy, busy_time);
|
||||
get_time_str(thread_info[i]->busy - thread_info[i]->last_busy, busy_time);
|
||||
print_max_len(g_tabs[THREADS_TAB], TABS_DATA_START_ROW + item_index, col,
|
||||
col_desc[6].max_data_string, ALIGN_RIGHT, busy_time);
|
||||
thread_info[i]->last_busy = thread_info[i]->busy;
|
||||
}
|
||||
}
|
||||
|
||||
return max_pages;
|
||||
}
|
||||
|
||||
static uint64_t *
|
||||
get_last_run_counter(const char *poller_name, uint64_t thread_id)
|
||||
{
|
||||
struct run_counter_history *history;
|
||||
|
||||
TAILQ_FOREACH(history, &g_run_counter_history, link) {
|
||||
if (!strcmp(history->poller_name, poller_name) && history->thread_id == thread_id) {
|
||||
return &history->last_run_counter;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
store_last_run_counter(const char *poller_name, uint64_t thread_id, uint64_t last_run_counter)
|
||||
{
|
||||
struct run_counter_history *history;
|
||||
|
||||
TAILQ_FOREACH(history, &g_run_counter_history, link) {
|
||||
if (!strcmp(history->poller_name, poller_name) && history->thread_id == thread_id) {
|
||||
history->last_run_counter = last_run_counter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
history = calloc(1, sizeof(*history));
|
||||
history->poller_name = strdup(poller_name);
|
||||
history->thread_id = thread_id;
|
||||
history->last_run_counter = last_run_counter;
|
||||
|
||||
TAILQ_INSERT_TAIL(&g_run_counter_history, history, link);
|
||||
}
|
||||
|
||||
enum sort_type {
|
||||
BY_NAME,
|
||||
USE_GLOBAL,
|
||||
@ -902,6 +963,7 @@ sort_pollers(const void *p1, const void *p2, void *arg)
|
||||
const struct rpc_poller_info *poller2 = *(struct rpc_poller_info **)p2;
|
||||
enum sort_type sorting = *(enum sort_type *)arg;
|
||||
uint64_t count1, count2;
|
||||
uint64_t *last_run_counter;
|
||||
|
||||
if (sorting == BY_NAME) {
|
||||
/* Sorting by name requested explicitly */
|
||||
@ -916,8 +978,10 @@ sort_pollers(const void *p1, const void *p2, void *arg)
|
||||
case 2: /* Sort by thread */
|
||||
return strcmp(poller1->thread_name, poller2->thread_name);
|
||||
case 3: /* Sort by run counter */
|
||||
count1 = poller1->run_count;
|
||||
count2 = poller2->run_count;
|
||||
last_run_counter = get_last_run_counter(poller1->name, poller1->thread_id);
|
||||
count1 = poller1->run_count - *last_run_counter;
|
||||
last_run_counter = get_last_run_counter(poller2->name, poller2->thread_id);
|
||||
count2 = poller2->run_count - *last_run_counter;
|
||||
break;
|
||||
case 4: /* Sort by period */
|
||||
count1 = poller1->period_ticks;
|
||||
@ -939,14 +1003,25 @@ sort_pollers(const void *p1, const void *p2, void *arg)
|
||||
|
||||
static void
|
||||
copy_pollers(struct rpc_pollers *pollers, uint64_t pollers_count, enum spdk_poller_type type,
|
||||
struct rpc_poller_thread_info *thread, uint64_t *current_count,
|
||||
struct rpc_poller_thread_info *thread, uint64_t *current_count, bool reset_last_counter,
|
||||
struct rpc_poller_info **pollers_info)
|
||||
{
|
||||
uint64_t *last_run_counter;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < pollers_count; i++) {
|
||||
if (reset_last_counter) {
|
||||
last_run_counter = get_last_run_counter(pollers->pollers[i].name, thread->id);
|
||||
if (last_run_counter == NULL) {
|
||||
store_last_run_counter(pollers->pollers[i].name, thread->id, pollers->pollers[i].run_count);
|
||||
last_run_counter = get_last_run_counter(pollers->pollers[i].name, thread->id);
|
||||
}
|
||||
|
||||
*last_run_counter = pollers->pollers[i].run_count;
|
||||
}
|
||||
pollers_info[*current_count] = &pollers->pollers[i];
|
||||
snprintf(pollers_info[*current_count]->thread_name, MAX_POLLER_NAME - 1, "%s", thread->name);
|
||||
pollers_info[*current_count]->thread_id = thread->id;
|
||||
pollers_info[(*current_count)++]->type = type;
|
||||
}
|
||||
}
|
||||
@ -956,22 +1031,34 @@ refresh_pollers_tab(uint8_t current_page)
|
||||
{
|
||||
struct col_desc *col_desc = g_col_desc[POLLERS_TAB];
|
||||
struct rpc_poller_thread_info *thread;
|
||||
uint64_t *last_run_counter;
|
||||
uint64_t i, count = 0;
|
||||
uint16_t col, j;
|
||||
uint8_t max_pages, item_index;
|
||||
/* Init g_last_page with value != 0 to force store_last_run_counter() call in copy_pollers()
|
||||
* so that initial values for run_counter are stored in g_run_counter_history */
|
||||
static uint8_t g_last_page = 0xF;
|
||||
enum sort_type sorting;
|
||||
char run_count[MAX_TIME_STR_LEN], period_ticks[MAX_PERIOD_STR_LEN];
|
||||
struct rpc_poller_info *pollers[RPC_MAX_POLLERS];
|
||||
bool reset_last_counter = false;
|
||||
|
||||
for (i = 0; i < g_pollers_stats.pollers_threads.threads_count; i++) {
|
||||
thread = &g_pollers_stats.pollers_threads.threads[i];
|
||||
if (g_last_page != current_page) {
|
||||
reset_last_counter = true;
|
||||
}
|
||||
|
||||
copy_pollers(&thread->active_pollers, thread->active_pollers.pollers_count, SPDK_ACTIVE_POLLER,
|
||||
thread, &count, pollers);
|
||||
thread, &count, reset_last_counter, pollers);
|
||||
copy_pollers(&thread->timed_pollers, thread->timed_pollers.pollers_count, SPDK_TIMED_POLLER, thread,
|
||||
&count, pollers);
|
||||
&count, reset_last_counter, pollers);
|
||||
copy_pollers(&thread->paused_pollers, thread->paused_pollers.pollers_count, SPDK_PAUSED_POLLER,
|
||||
thread, &count, pollers);
|
||||
thread, &count, reset_last_counter, pollers);
|
||||
}
|
||||
|
||||
if (g_last_page != current_page) {
|
||||
g_last_page = current_page;
|
||||
}
|
||||
|
||||
/* Clear screen if number of pollers changed */
|
||||
@ -1021,10 +1108,14 @@ refresh_pollers_tab(uint8_t current_page)
|
||||
}
|
||||
|
||||
if (!col_desc[3].disabled) {
|
||||
snprintf(run_count, MAX_TIME_STR_LEN, "%" PRIu64, pollers[i]->run_count);
|
||||
last_run_counter = get_last_run_counter(pollers[i]->name, pollers[i]->thread_id);
|
||||
|
||||
snprintf(run_count, MAX_TIME_STR_LEN, "%" PRIu64, pollers[i]->run_count - *last_run_counter);
|
||||
print_max_len(g_tabs[POLLERS_TAB], TABS_DATA_START_ROW + item_index, col,
|
||||
col_desc[3].max_data_string, ALIGN_RIGHT, run_count);
|
||||
col += col_desc[3].max_data_string + 2;
|
||||
col += col_desc[3].max_data_string;
|
||||
|
||||
store_last_run_counter(pollers[i]->name, pollers[i]->thread_id, pollers[i]->run_count);
|
||||
}
|
||||
|
||||
if (!col_desc[4].disabled) {
|
||||
@ -1060,12 +1151,12 @@ sort_cores(const void *p1, const void *p2)
|
||||
count2 = core_info2.pollers_count;
|
||||
break;
|
||||
case 3: /* Sort by idle time */
|
||||
count1 = core_info1.idle;
|
||||
count2 = core_info2.idle;
|
||||
count2 = g_cores_history[core_info1.core].last_idle - core_info1.idle;
|
||||
count1 = g_cores_history[core_info2.core].last_idle - core_info2.idle;
|
||||
break;
|
||||
case 4: /* Sort by busy time */
|
||||
count1 = core_info1.busy;
|
||||
count2 = core_info2.busy;
|
||||
count2 = g_cores_history[core_info1.core].last_busy - core_info1.busy;
|
||||
count1 = g_cores_history[core_info2.core].last_busy - core_info2.busy;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -1080,6 +1171,20 @@ sort_cores(const void *p1, const void *p2)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
store_core_last_stats(uint32_t core, uint64_t idle, uint64_t busy)
|
||||
{
|
||||
g_cores_history[core].last_idle = idle;
|
||||
g_cores_history[core].last_busy = busy;
|
||||
}
|
||||
|
||||
static void
|
||||
get_core_last_stats(uint32_t core, uint64_t *idle, uint64_t *busy)
|
||||
{
|
||||
*idle = g_cores_history[core].last_idle;
|
||||
*busy = g_cores_history[core].last_busy;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
refresh_cores_tab(uint8_t current_page)
|
||||
{
|
||||
@ -1087,6 +1192,7 @@ refresh_cores_tab(uint8_t current_page)
|
||||
uint64_t i, j;
|
||||
uint16_t offset, count = 0;
|
||||
uint8_t max_pages, item_index;
|
||||
static uint8_t last_page = 0;
|
||||
char core[MAX_CORE_STR_LEN], threads_number[MAX_THREAD_COUNT_STR_LEN],
|
||||
pollers_number[MAX_POLLER_COUNT_STR_LEN], idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];
|
||||
struct core_info cores[RPC_MAX_CORES];
|
||||
@ -1138,10 +1244,16 @@ refresh_cores_tab(uint8_t current_page)
|
||||
cores[i].core = g_cores_stats.cores.core[j].lcore;
|
||||
cores[i].busy = g_cores_stats.cores.core[j].busy;
|
||||
cores[i].idle = g_cores_stats.cores.core[j].idle;
|
||||
if (last_page != current_page) {
|
||||
store_core_last_stats(cores[i].core, cores[i].idle, cores[i].busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_page != current_page) {
|
||||
last_page = current_page;
|
||||
}
|
||||
|
||||
max_pages = (count + g_max_row - WINDOW_HEADER - 1) / (g_max_row - WINDOW_HEADER);
|
||||
|
||||
@ -1154,6 +1266,7 @@ refresh_cores_tab(uint8_t current_page)
|
||||
|
||||
snprintf(threads_number, MAX_THREAD_COUNT_STR_LEN, "%ld", cores[i].threads_count);
|
||||
snprintf(pollers_number, MAX_POLLER_COUNT_STR_LEN, "%ld", cores[i].pollers_count);
|
||||
get_core_last_stats(cores[i].core, &cores[i].last_idle, &cores[i].last_busy);
|
||||
|
||||
offset = 1;
|
||||
|
||||
@ -1177,17 +1290,19 @@ refresh_cores_tab(uint8_t current_page)
|
||||
}
|
||||
|
||||
if (!col_desc[3].disabled) {
|
||||
get_time_str(cores[i].idle, idle_time);
|
||||
get_time_str(cores[i].idle - cores[i].last_idle, idle_time);
|
||||
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, offset,
|
||||
col_desc[3].max_data_string, ALIGN_RIGHT, idle_time);
|
||||
offset += col_desc[3].max_data_string + 2;
|
||||
}
|
||||
|
||||
if (!col_desc[4].disabled) {
|
||||
get_time_str(cores[i].busy, busy_time);
|
||||
get_time_str(cores[i].busy - cores[i].last_busy, busy_time);
|
||||
print_max_len(g_tabs[CORES_TAB], TABS_DATA_START_ROW + item_index, offset,
|
||||
col_desc[4].max_data_string, ALIGN_RIGHT, busy_time);
|
||||
}
|
||||
|
||||
store_core_last_stats(cores[i].core, cores[i].idle, cores[i].busy);
|
||||
}
|
||||
|
||||
return max_pages;
|
||||
@ -1504,6 +1619,18 @@ change_sorting(uint8_t tab)
|
||||
draw_menu_win();
|
||||
}
|
||||
|
||||
static void
|
||||
free_resources(void)
|
||||
{
|
||||
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->poller_name);
|
||||
free(history);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_stats(void)
|
||||
{
|
||||
@ -1532,6 +1659,7 @@ show_stats(void)
|
||||
|
||||
c = getch();
|
||||
if (c == 'q') {
|
||||
free_resources();
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user