test/scheduler: change how test threads consume cpu cycles

Now a test thread will have one idle_poller and an optional
busy poller (when active_percent > 0).

The idle poller will just consume a very small amount of
tsc via spdk_delay_us(10).

If active_percent > 0, we will start a timed poller for
TIMESLICE_US (currently 100 * 1000).  When that timer
expires, it will consume TIMESLICE_US * active_percent
microseconds.

I think this is a slightly simpler way to enforce the
thread consumption percentages specified by the tests.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: I13dd18dacff0f6a86c045876384a8931b7273842

Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9654
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Jim Harris 2021-09-27 05:47:37 -07:00 committed by Tomasz Zawadzki
parent 15535803d4
commit e8c467965e

View File

@ -45,16 +45,13 @@
static bool g_is_running = true; static bool g_is_running = true;
pthread_mutex_t g_sched_list_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t g_sched_list_mutex = PTHREAD_MUTEX_INITIALIZER;
#define TIMESLICE_US 100 /* Execution time of single busy thread poll in us. */ #define TIMESLICE_US 100 * 1000
static uint64_t g_core_time_period;
static uint64_t g_timeslice_tsc;
struct sched_thread { struct sched_thread {
struct spdk_thread *thread; struct spdk_thread *thread;
struct spdk_poller *poller; struct spdk_poller *poller;
struct spdk_poller *idle_poller;
int active_percent; int active_percent;
uint64_t next_period_tsc;
uint64_t remaining_tsc;
struct spdk_jsonrpc_request *request; struct spdk_jsonrpc_request *request;
TAILQ_ENTRY(sched_thread) link; TAILQ_ENTRY(sched_thread) link;
}; };
@ -94,6 +91,7 @@ static void
thread_delete(struct sched_thread *sched_thread) thread_delete(struct sched_thread *sched_thread)
{ {
spdk_poller_unregister(&sched_thread->poller); spdk_poller_unregister(&sched_thread->poller);
spdk_poller_unregister(&sched_thread->idle_poller);
spdk_thread_exit(sched_thread->thread); spdk_thread_exit(sched_thread->thread);
TAILQ_REMOVE(&g_sched_threads, sched_thread, link); TAILQ_REMOVE(&g_sched_threads, sched_thread, link);
@ -105,10 +103,9 @@ thread_delete(struct sched_thread *sched_thread)
} }
static int static int
poller_run(void *arg) poller_run_busy(void *arg)
{ {
struct sched_thread *sched_thread = arg; struct sched_thread *sched_thread = arg;
uint64_t now;
if (spdk_unlikely(!g_is_running)) { if (spdk_unlikely(!g_is_running)) {
pthread_mutex_lock(&g_sched_list_mutex); pthread_mutex_lock(&g_sched_list_mutex);
@ -117,31 +114,48 @@ poller_run(void *arg)
return SPDK_POLLER_IDLE; return SPDK_POLLER_IDLE;
} }
now = spdk_get_ticks(); spdk_delay_us(TIMESLICE_US * sched_thread->active_percent / 100);
return SPDK_POLLER_BUSY;
}
/* Reset the timers once we go over single core time period */ static int
if (sched_thread->next_period_tsc <= now) { poller_run_idle(void *arg)
sched_thread->next_period_tsc = now + g_core_time_period; {
sched_thread->remaining_tsc = (g_core_time_period / 100) * sched_thread->active_percent; struct sched_thread *sched_thread = arg;
}
if (spdk_unlikely(!g_is_running)) {
if (sched_thread->remaining_tsc > 0) { pthread_mutex_lock(&g_sched_list_mutex);
spdk_delay_us(TIMESLICE_US); thread_delete(sched_thread);
sched_thread->remaining_tsc -= spdk_min(sched_thread->remaining_tsc, g_timeslice_tsc); pthread_mutex_unlock(&g_sched_list_mutex);
return SPDK_POLLER_BUSY; return SPDK_POLLER_IDLE;
} }
spdk_delay_us(10);
return SPDK_POLLER_IDLE; return SPDK_POLLER_IDLE;
} }
static void
update_pollers(struct sched_thread *sched_thread)
{
spdk_poller_unregister(&sched_thread->poller);
if (sched_thread->active_percent > 0) {
sched_thread->poller = spdk_poller_register_named(poller_run_busy, sched_thread, TIMESLICE_US,
spdk_thread_get_name(sched_thread->thread));
assert(sched_thread->poller != NULL);
}
if (sched_thread->idle_poller == NULL) {
sched_thread->idle_poller = spdk_poller_register_named(poller_run_idle, sched_thread, 0,
"idle_poller");
assert(sched_thread->idle_poller != NULL);
}
}
static void static void
rpc_register_poller(void *arg) rpc_register_poller(void *arg)
{ {
struct sched_thread *sched_thread = arg; struct sched_thread *sched_thread = arg;
sched_thread->poller = spdk_poller_register_named(poller_run, sched_thread, 0, update_pollers(sched_thread);
spdk_thread_get_name(sched_thread->thread));
assert(sched_thread->poller != NULL);
if (sched_thread->request != NULL) { if (sched_thread->request != NULL) {
rpc_scheduler_thread_create_cb(sched_thread->request, spdk_thread_get_id(sched_thread->thread)); rpc_scheduler_thread_create_cb(sched_thread->request, spdk_thread_get_id(sched_thread->thread));
@ -195,7 +209,6 @@ rpc_scheduler_thread_create(struct spdk_jsonrpc_request *request,
sched_thread->request = request; sched_thread->request = request;
sched_thread->active_percent = req.active_percent; sched_thread->active_percent = req.active_percent;
sched_thread->next_period_tsc = 0;
spdk_thread_send_msg(sched_thread->thread, rpc_register_poller, sched_thread); spdk_thread_send_msg(sched_thread->thread, rpc_register_poller, sched_thread);
@ -237,9 +250,8 @@ rpc_scheduler_thread_set_active_cb(void *arg)
pthread_mutex_lock(&g_sched_list_mutex); pthread_mutex_lock(&g_sched_list_mutex);
TAILQ_FOREACH(sched_thread, &g_sched_threads, link) { TAILQ_FOREACH(sched_thread, &g_sched_threads, link) {
if (spdk_thread_get_id(sched_thread->thread) == thread_id) { if (spdk_thread_get_id(sched_thread->thread) == thread_id) {
/* Reset next_period_tsc to force recalculation of remaining_tsc. */
sched_thread->next_period_tsc = 0;
sched_thread->active_percent = ctx->active_percent; sched_thread->active_percent = ctx->active_percent;
update_pollers(sched_thread);
pthread_mutex_unlock(&g_sched_list_mutex); pthread_mutex_unlock(&g_sched_list_mutex);
spdk_jsonrpc_send_bool_response(ctx->request, true); spdk_jsonrpc_send_bool_response(ctx->request, true);
free(ctx); free(ctx);
@ -381,11 +393,6 @@ test_shutdown(void)
static void static void
test_start(void *arg1) test_start(void *arg1)
{ {
/* Hardcode g_core_time_period as 100ms. */
g_core_time_period = spdk_get_ticks_hz() / 10;
/* Hardcode g_timeslice_tsc as 100us. */
g_timeslice_tsc = spdk_get_ticks_hz() / SPDK_SEC_TO_USEC * TIMESLICE_US;
SPDK_NOTICELOG("Scheduler test application started.\n"); SPDK_NOTICELOG("Scheduler test application started.\n");
} }