From a2079b3f7d83091e2616519e059732b60e52bdf6 Mon Sep 17 00:00:00 2001 From: Maciej Szwed Date: Thu, 9 Apr 2020 10:32:00 +0200 Subject: [PATCH] spdk_top: Make data relative to last refresh Signed-off-by: Maciej Szwed Change-Id: Icea3c66173f3d7bedcb34dbe353b7753885c06ad Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1776 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- app/spdk_top/spdk_top.c | 182 ++++++++++++++++++++++++++++++++++------ 1 file changed, 155 insertions(+), 27 deletions(-) diff --git a/app/spdk_top/spdk_top.c b/app/spdk_top/spdk_top.c index fade3077c..46fbe60c9 100644 --- a/app/spdk_top/spdk_top.c +++ b/app/spdk_top/spdk_top.c @@ -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; }