Commit fbcfcb98 authored by Krzysztof Karas's avatar Krzysztof Karas Committed by Tomasz Zawadzki
Browse files

spdk_top: separate data gathering logic from data display



Separates data gathering logic in tabs. Data is now being collected
on a separate thread.
Modified wait_init() and show_stats() to allow for thread creation
when starting spdk_top and thread join when closing.

Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Change-Id: I54a58522f31f938e2d1275c3a6f60fe8c17b0031
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6368


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
parent 57837813
Loading
Loading
Loading
Loading
+92 −18
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ uint16_t g_data_win_size, g_max_data_rows;
uint32_t g_last_threads_count, g_last_pollers_count, g_last_cores_count;
uint8_t g_current_sort_col[NUMBER_OF_TABS] = {0, 0, 0};
bool g_interval_data = true;
bool g_quit_app = false;
pthread_mutex_t g_thread_lock;
static struct col_desc g_col_desc[NUMBER_OF_TABS][TABS_COL_COUNT] = {
	{	{.name = "Thread name", .max_data_string = MAX_THREAD_NAME_LEN},
		{.name = "Core", .max_data_string = MAX_CORE_STR_LEN},
@@ -1962,6 +1964,7 @@ display_thread(struct rpc_thread_info *thread_info)
	bool stop_loop = false;
	char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN], run_count[MAX_POLLER_COUNT_STR_LEN];

	pthread_mutex_lock(&g_thread_lock);
	pollers_count = thread_info->active_pollers_count +
			thread_info->timed_pollers_count +
			thread_info->paused_pollers_count;
@@ -2054,6 +2057,7 @@ display_thread(struct rpc_thread_info *thread_info)
	refresh();
	wrefresh(thread_win);

	pthread_mutex_unlock(&g_thread_lock);
	while (!stop_loop) {
		c = wgetch(thread_win);

@@ -2076,8 +2080,10 @@ show_thread(uint8_t current_page)
	struct rpc_thread_info thread_info;
	uint64_t thread_number = current_page * g_max_data_rows + g_selected_row;

	pthread_mutex_lock(&g_thread_lock);
	assert(thread_number < g_threads_stats.threads.threads_count);
	thread_info = g_threads_stats.threads.thread_info[thread_number];
	pthread_mutex_unlock(&g_thread_lock);

	display_thread(&thread_info);
}
@@ -2086,13 +2092,18 @@ static void
show_single_thread(uint64_t thread_id)
{
	uint64_t i;
	struct rpc_thread_info thread_info;

	pthread_mutex_lock(&g_thread_lock);
	for (i = 0; i < g_threads_stats.threads.threads_count; i++) {
		if (g_threads_stats.threads.thread_info[i].id == thread_id) {
			display_thread(&g_threads_stats.threads.thread_info[i]);
			break;
			thread_info = g_threads_stats.threads.thread_info[i];
			pthread_mutex_unlock(&g_thread_lock);
			display_thread(&thread_info);
			return;
		}
	}
	pthread_mutex_unlock(&g_thread_lock);
}

static void
@@ -2103,18 +2114,21 @@ show_core(uint8_t current_page)
	uint64_t core_number = current_page * g_max_data_rows + g_selected_row;
	struct rpc_core_info *core_info[g_cores_stats.cores.cores_count];
	uint64_t threads_count, i, j;
	uint64_t thread_id;
	uint16_t current_threads_row;
	int c;
	char core_win_title[25];
	bool stop_loop = false;
	char idle_time[MAX_TIME_STR_LEN], busy_time[MAX_TIME_STR_LEN];

	pthread_mutex_lock(&g_thread_lock);
	assert(core_number < g_cores_stats.cores.cores_count);
	for (i = 0; i < g_cores_stats.cores.cores_count; i++) {
		core_info[i] = &g_cores_stats.cores.core[i];
	}

	threads_count = g_cores_stats.cores.core->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));
@@ -2171,6 +2185,7 @@ show_core(uint8_t current_page)
	for (j = 0; j < core_info[core_number]->threads.threads_count; j++) {
		mvwprintw(core_win, j + 10, 1, core_info[core_number]->threads.thread[j].name);
	}
	pthread_mutex_unlock(&g_thread_lock);

	refresh();
	wrefresh(core_win);
@@ -2178,6 +2193,7 @@ show_core(uint8_t current_page)
	current_threads_row = 0;

	while (!stop_loop) {
		pthread_mutex_lock(&g_thread_lock);
		for (j = 0; j < core_info[core_number]->threads.threads_count; j++) {
			if (j != current_threads_row) {
				mvwprintw(core_win, j + 10, 1, core_info[core_number]->threads.thread[j].name);
@@ -2186,13 +2202,17 @@ show_core(uint8_t current_page)
					   core_info[core_number]->threads.thread[j].name, COLOR_PAIR(2));
			}
		}
		pthread_mutex_unlock(&g_thread_lock);

		wrefresh(core_win);

		c = wgetch(core_win);
		switch (c) {
		case 10: /* ENTER */
			show_single_thread(core_info[core_number]->threads.thread[current_threads_row].id);
			pthread_mutex_lock(&g_thread_lock);
			thread_id = core_info[core_number]->threads.thread[current_threads_row].id;
			pthread_mutex_unlock(&g_thread_lock);
			show_single_thread(thread_id);
			break;
		case 27: /* ESC */
			stop_loop = true;
@@ -2203,9 +2223,11 @@ show_core(uint8_t current_page)
			}
			break;
		case KEY_DOWN:
			pthread_mutex_lock(&g_thread_lock);
			if (current_threads_row != core_info[core_number]->threads.threads_count - 1) {
				current_threads_row++;
			}
			pthread_mutex_unlock(&g_thread_lock);
			break;
		default:
			break;
@@ -2229,6 +2251,7 @@ show_poller(uint8_t current_page)
	char poller_period[MAX_TIME_STR_LEN];
	int c;

	pthread_mutex_lock(&g_thread_lock);
	prepare_poller_data(current_page, pollers, &count, current_page);
	assert(poller_number < count);

@@ -2285,6 +2308,7 @@ show_poller(uint8_t current_page)
	refresh();
	wrefresh(poller_win);

	pthread_mutex_unlock(&g_thread_lock);
	while (!stop_loop) {
		c = wgetch(poller_win);
		switch (c) {
@@ -2300,14 +2324,38 @@ show_poller(uint8_t current_page)
	delwin(poller_win);
}

static void *
data_thread_routine(void *arg)
{
	int rc;
	const char *get_data_error = "ERROR occurred while getting data";

	while (1) {
		pthread_mutex_lock(&g_thread_lock);
		if (g_quit_app) {
			pthread_mutex_unlock(&g_thread_lock);
			break;
		}

		rc = get_data();
		if (rc) {
			mvprintw(g_max_row - 1, g_max_col - strlen(get_data_error) - 2, get_data_error);
		}

		pthread_mutex_unlock(&g_thread_lock);
		usleep(g_sleep_time);
	}

	return NULL;
}

static void
show_stats(void)
show_stats(pthread_t *data_thread)
{
	const int CURRENT_PAGE_STR_LEN = 50;
	const char *refresh_error = "ERROR occurred while getting data";
	long int time_last, time_dif;
	struct timespec time_now;
	int c, rc;
	int c;
	int max_row, max_col;
	uint8_t active_tab = THREADS_TAB;
	uint8_t current_page = 0;
@@ -2319,8 +2367,6 @@ show_stats(void)
	clock_gettime(CLOCK_REALTIME, &time_now);
	time_last = time_now.tv_sec;

	memset(&g_threads_stats, 0, sizeof(g_threads_stats));

	switch_tab(THREADS_TAB);

	while (1) {
@@ -2343,12 +2389,9 @@ show_stats(void)

		if (time_dif >= g_sleep_time || force_refresh) {
			time_last = time_now.tv_sec;
			rc = get_data();
			if (rc) {
				mvprintw(g_max_row - 1, g_max_col - strlen(refresh_error) - 2, refresh_error);
			}

			pthread_mutex_lock(&g_thread_lock);
			max_pages = refresh_tab(active_tab, current_page);
			pthread_mutex_unlock(&g_thread_lock);

			snprintf(current_page_str, CURRENT_PAGE_STR_LEN - 1, "Page: %d/%d", current_page + 1, max_pages);
			mvprintw(g_max_row - 1, 1, current_page_str);
@@ -2358,7 +2401,9 @@ show_stats(void)

		c = getch();
		if (c == 'q') {
			free_resources();
			pthread_mutex_lock(&g_thread_lock);
			g_quit_app = true;
			pthread_mutex_unlock(&g_thread_lock);
			break;
		}

@@ -2435,6 +2480,10 @@ show_stats(void)
			break;
		}
	}

	pthread_join(*data_thread, NULL);

	free_resources();
	free_data();
}

@@ -2471,7 +2520,8 @@ draw_interface(void)
	doupdate();
}

static void finish(int sig)
static void
finish(int sig)
{
	/* End ncurses mode */
	endwin();
@@ -2521,7 +2571,7 @@ usage(const char *program_name)
}

static int
wait_init(void)
wait_init(pthread_t *data_thread)
{
	struct spdk_jsonrpc_client_response *json_resp = NULL;
	char *uninit_log = "Waiting for SPDK target application to initialize...",
@@ -2544,6 +2594,29 @@ wait_init(void)
	}

	spdk_jsonrpc_client_free_response(json_resp);

	rc = pthread_mutex_init(&g_thread_lock, NULL);
	if (rc) {
		fprintf(stderr, "mutex lock failed to initialize: %d\n", errno);
		return -1;
	}

	memset(&g_threads_stats, 0, sizeof(g_threads_stats));

	/* This is to get first batch of data for display functions.
	 * Since data thread makes RPC calls that take more time than
	 * startup of display functions on main thread, without this
	 * call both threads would be subject to a race condition. */
	rc = get_data();
	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;
	}
	return 0;
}

@@ -2551,6 +2624,7 @@ int main(int argc, char **argv)
{
	int op, rc;
	char *socket = SPDK_DEFAULT_RPC_ADDR;
	pthread_t data_thread;

	while ((op = getopt(argc, argv, "r:h")) != -1) {
		switch (op) {
@@ -2574,9 +2648,9 @@ int main(int argc, char **argv)
	setup_ncurses();
	draw_interface();

	rc = wait_init();
	rc = wait_init(&data_thread);
	if (!rc) {
		show_stats();
		show_stats(&data_thread);
	}

	finish(0);